提交 2dd3a88a 编写于 作者: D Dave Airlie

Merge tag 'drm-intel-next-2015-10-10' of git://anongit.freedesktop.org/drm-intel into drm-next

- dmc fixes from Animesh (not yet all) for deeper sleep states
- piles of prep patches from Ville to make mmio functions type-safe
- more fbc work from Paulo all over
- w/a shuffling from Arun Siluvery
- first part of atomic watermark updates from Matt and Ville (later parts had to
  be dropped again unfortunately)
- lots of patches to prepare bxt dsi support ( Shashank Sharma)
- userptr fixes from Chris
- audio rate interface between i915/snd_hda plus kerneldoc (Libin Yang)
- shrinker improvements and fixes (Chris Wilson)
- lots and lots of small patches all over

* tag 'drm-intel-next-2015-10-10' of git://anongit.freedesktop.org/drm-intel: (134 commits)
  drm/i915: Update DRIVER_DATE to 20151010
  drm/i915: Partial revert of atomic watermark series
  drm/i915: Early exit from semaphore_waits_for for execlist mode.
  drm/i915: Remove wrong warning from i915_gem_context_clean
  drm/i915: Determine the stolen memory base address on gen2
  drm/i915: fix FBC buffer size checks
  drm/i915: fix CFB size calculation
  drm/i915: remove pre-atomic check from SKL update_primary_plane
  drm/i915: don't allocate fbcon from stolen memory if it's too big
  Revert "drm/i915: Call encoder hotplug for init and resume cases"
  Revert "drm/i915: Add hot_plug hook for hdmi encoder"
  drm/i915: use error path
  drm/i915/irq: Fix misspelled word register in kernel-doc
  drm/i915/irq: Fix kernel-doc warnings
  drm/i915: Hook up ring workaround writes at context creation time on Gen6-7.
  drm/i915: Don't warn if the workaround list is empty.
  drm/i915: Resurrect golden context on gen6/7
  drm/i915/chv: remove pre-production hardware workarounds
  drm/i915/snb: remove pre-production hardware workaround
  drm/i915/bxt: Set time interval unit to 0.833us
  ...
...@@ -3989,6 +3989,7 @@ int num_ioctls;</synopsis> ...@@ -3989,6 +3989,7 @@ int num_ioctls;</synopsis>
<title>High Definition Audio</title> <title>High Definition Audio</title>
!Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port !Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port
!Idrivers/gpu/drm/i915/intel_audio.c !Idrivers/gpu/drm/i915/intel_audio.c
!Iinclude/drm/i915_component.h
</sect2> </sect2>
<sect2> <sect2>
<title>Panel Self Refresh PSR (PSR/SRD)</title> <title>Panel Self Refresh PSR (PSR/SRD)</title>
......
...@@ -94,8 +94,8 @@ struct intel_dvo_dev_ops { ...@@ -94,8 +94,8 @@ struct intel_dvo_dev_ops {
* after this function is called. * after this function is called.
*/ */
void (*mode_set)(struct intel_dvo_device *dvo, void (*mode_set)(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); const struct drm_display_mode *adjusted_mode);
/* /*
* Probe for a connected output, and return detect_status. * Probe for a connected output, and return detect_status.
......
...@@ -255,8 +255,8 @@ static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, ...@@ -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, static void ch7017_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; uint8_t lvds_pll_feedback_div, lvds_pll_vco_control;
uint8_t outputs_enable, lvds_control_2, lvds_power_down; uint8_t outputs_enable, lvds_control_2, lvds_power_down;
......
...@@ -275,8 +275,8 @@ static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, ...@@ -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, static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
uint8_t tvco, tpcp, tpd, tlpf, idf; uint8_t tvco, tpcp, tpd, tlpf, idf;
......
...@@ -394,8 +394,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo) ...@@ -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, static void ivch_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
struct ivch_priv *priv = dvo->dev_priv; struct ivch_priv *priv = dvo->dev_priv;
uint16_t vr40 = 0; uint16_t vr40 = 0;
...@@ -414,16 +414,16 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, ...@@ -414,16 +414,16 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
VR40_HORIZONTAL_INTERP_ENABLE); VR40_HORIZONTAL_INTERP_ENABLE);
if (mode->hdisplay != adjusted_mode->hdisplay || if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
mode->vdisplay != adjusted_mode->vdisplay) { mode->vdisplay != adjusted_mode->crtc_vdisplay) {
uint16_t x_ratio, y_ratio; uint16_t x_ratio, y_ratio;
vr01 |= VR01_PANEL_FIT_ENABLE; vr01 |= VR01_PANEL_FIT_ENABLE;
vr40 |= VR40_CLOCK_GATING_ENABLE; vr40 |= VR40_CLOCK_GATING_ENABLE;
x_ratio = (((mode->hdisplay - 1) << 16) / x_ratio = (((mode->hdisplay - 1) << 16) /
(adjusted_mode->hdisplay - 1)) >> 2; (adjusted_mode->crtc_hdisplay - 1)) >> 2;
y_ratio = (((mode->vdisplay - 1) << 16) / 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, VR42, x_ratio);
ivch_write(dvo, VR41, y_ratio); ivch_write(dvo, VR41, y_ratio);
} else { } else {
......
...@@ -546,8 +546,8 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo, ...@@ -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, static void ns2501_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
const struct ns2501_configuration *conf; const struct ns2501_configuration *conf;
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv); struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
......
...@@ -190,8 +190,8 @@ static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, ...@@ -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, static void sil164_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
/* As long as the basics are set up, since we don't have clock /* As long as the basics are set up, since we don't have clock
* dependencies in the mode setup, we can just leave the * dependencies in the mode setup, we can just leave the
......
...@@ -222,8 +222,8 @@ static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, ...@@ -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, static void tfp410_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *mode, const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) const struct drm_display_mode *adjusted_mode)
{ {
/* As long as the basics are set up, since we don't have clock dependencies /* 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 * in the mode setup, we can just leave the registers alone and everything
......
...@@ -448,6 +448,9 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = { ...@@ -448,6 +448,9 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
REG32(GEN7_3DPRIM_INSTANCE_COUNT), REG32(GEN7_3DPRIM_INSTANCE_COUNT),
REG32(GEN7_3DPRIM_START_INSTANCE), REG32(GEN7_3DPRIM_START_INSTANCE),
REG32(GEN7_3DPRIM_BASE_VERTEX), 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(0)),
REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)),
REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)),
...@@ -1214,6 +1217,7 @@ int i915_cmd_parser_get_version(void) ...@@ -1214,6 +1217,7 @@ int i915_cmd_parser_get_version(void)
* MI_PREDICATE_SRC1 registers. * MI_PREDICATE_SRC1 registers.
* 3. Allow access to the GPGPU_THREADS_DISPATCHED register. * 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
* 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3. * 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3.
* 5. GPGPU dispatch compute indirect registers.
*/ */
return 4; return 5;
} }
...@@ -253,7 +253,11 @@ static int obj_rank_by_stolen(void *priv, ...@@ -253,7 +253,11 @@ static int obj_rank_by_stolen(void *priv,
struct drm_i915_gem_object *b = struct drm_i915_gem_object *b =
container_of(B, struct drm_i915_gem_object, obj_exec_link); 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) static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
...@@ -1308,6 +1312,10 @@ static int i915_frequency_info(struct seq_file *m, void *unused) ...@@ -1308,6 +1312,10 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_puts(m, "no P-state info available\n"); 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: out:
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
return ret; return ret;
...@@ -2230,10 +2238,9 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev) ...@@ -2230,10 +2238,9 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
for_each_ring(ring, dev_priv, unused) { for_each_ring(ring, dev_priv, unused) {
seq_printf(m, "%s\n", ring->name); seq_printf(m, "%s\n", ring->name);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
u32 offset = 0x270 + i * 8; u64 pdp = I915_READ(GEN8_RING_PDP_UDW(ring, i));
u64 pdp = I915_READ(ring->mmio_base + offset + 4);
pdp <<= 32; 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); seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp);
} }
} }
...@@ -2290,18 +2297,21 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) ...@@ -2290,18 +2297,21 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
struct task_struct *task; struct task_struct *task;
task = get_pid_task(file->pid, PIDTYPE_PID); task = get_pid_task(file->pid, PIDTYPE_PID);
if (!task) if (!task) {
return -ESRCH; ret = -ESRCH;
goto out_put;
}
seq_printf(m, "\nproc: %s\n", task->comm); seq_printf(m, "\nproc: %s\n", task->comm);
put_task_struct(task); put_task_struct(task);
idr_for_each(&file_priv->context_idr, per_file_ctx, idr_for_each(&file_priv->context_idr, per_file_ctx,
(void *)(unsigned long)m); (void *)(unsigned long)m);
} }
out_put:
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0; return ret;
} }
static int count_irq_waiters(struct drm_i915_private *i915) static int count_irq_waiters(struct drm_i915_private *i915)
...@@ -2909,7 +2919,7 @@ static bool cursor_active(struct drm_device *dev, int pipe) ...@@ -2909,7 +2919,7 @@ static bool cursor_active(struct drm_device *dev, int pipe)
u32 state; u32 state;
if (IS_845G(dev) || IS_I865G(dev)) if (IS_845G(dev) || IS_I865G(dev))
state = I915_READ(_CURACNTR) & CURSOR_ENABLE; state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
else else
state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE; state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
...@@ -3147,7 +3157,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused) ...@@ -3147,7 +3157,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
skl_ddb_entry_size(entry)); 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, seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start,
entry->end, skl_ddb_entry_size(entry)); entry->end, skl_ddb_entry_size(entry));
} }
...@@ -5040,13 +5050,38 @@ static void gen9_sseu_device_status(struct drm_device *dev, ...@@ -5040,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) static int i915_sseu_status(struct seq_file *m, void *unused)
{ {
struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = node->minor->dev;
struct sseu_dev_status stat; struct sseu_dev_status stat;
if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev)) if (INTEL_INFO(dev)->gen < 8)
return -ENODEV; return -ENODEV;
seq_puts(m, "SSEU Device Info\n"); seq_puts(m, "SSEU Device Info\n");
...@@ -5071,6 +5106,8 @@ static int i915_sseu_status(struct seq_file *m, void *unused) ...@@ -5071,6 +5106,8 @@ static int i915_sseu_status(struct seq_file *m, void *unused)
memset(&stat, 0, sizeof(stat)); memset(&stat, 0, sizeof(stat));
if (IS_CHERRYVIEW(dev)) { if (IS_CHERRYVIEW(dev)) {
cherryview_sseu_device_status(dev, &stat); cherryview_sseu_device_status(dev, &stat);
} else if (IS_BROADWELL(dev)) {
broadwell_sseu_device_status(dev, &stat);
} else if (INTEL_INFO(dev)->gen >= 9) { } else if (INTEL_INFO(dev)->gen >= 9) {
gen9_sseu_device_status(dev, &stat); gen9_sseu_device_status(dev, &stat);
} }
......
...@@ -673,6 +673,82 @@ static void gen9_sseu_info_init(struct drm_device *dev) ...@@ -673,6 +673,82 @@ static void gen9_sseu_info_init(struct drm_device *dev)
info->has_eu_pg = (info->eu_per_subslice > 2); 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. * Determine various intel_device_info fields at runtime.
* *
...@@ -743,6 +819,8 @@ static void intel_device_info_runtime_init(struct drm_device *dev) ...@@ -743,6 +819,8 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
/* Initialize slice/subslice/EU info */ /* Initialize slice/subslice/EU info */
if (IS_CHERRYVIEW(dev)) if (IS_CHERRYVIEW(dev))
cherryview_sseu_info_init(dev); cherryview_sseu_info_init(dev);
else if (IS_BROADWELL(dev))
broadwell_sseu_info_init(dev);
else if (INTEL_INFO(dev)->gen >= 9) else if (INTEL_INFO(dev)->gen >= 9)
gen9_sseu_info_init(dev); gen9_sseu_info_init(dev);
...@@ -818,6 +896,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -818,6 +896,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
mutex_init(&dev_priv->sb_lock); mutex_init(&dev_priv->sb_lock);
mutex_init(&dev_priv->modeset_restore_lock); mutex_init(&dev_priv->modeset_restore_lock);
mutex_init(&dev_priv->csr_lock); mutex_init(&dev_priv->csr_lock);
mutex_init(&dev_priv->av_mutex);
intel_pm_setup(dev); intel_pm_setup(dev);
...@@ -1045,11 +1124,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1045,11 +1124,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
put_bridge: put_bridge:
pci_dev_put(dev_priv->bridge_dev); pci_dev_put(dev_priv->bridge_dev);
free_priv: free_priv:
if (dev_priv->requests)
kmem_cache_destroy(dev_priv->requests); kmem_cache_destroy(dev_priv->requests);
if (dev_priv->vmas)
kmem_cache_destroy(dev_priv->vmas); kmem_cache_destroy(dev_priv->vmas);
if (dev_priv->objects)
kmem_cache_destroy(dev_priv->objects); kmem_cache_destroy(dev_priv->objects);
kfree(dev_priv); kfree(dev_priv);
return ret; return ret;
...@@ -1141,13 +1217,9 @@ int i915_driver_unload(struct drm_device *dev) ...@@ -1141,13 +1217,9 @@ int i915_driver_unload(struct drm_device *dev)
if (dev_priv->regs != NULL) if (dev_priv->regs != NULL)
pci_iounmap(dev->pdev, dev_priv->regs); pci_iounmap(dev->pdev, dev_priv->regs);
if (dev_priv->requests)
kmem_cache_destroy(dev_priv->requests); kmem_cache_destroy(dev_priv->requests);
if (dev_priv->vmas)
kmem_cache_destroy(dev_priv->vmas); kmem_cache_destroy(dev_priv->vmas);
if (dev_priv->objects)
kmem_cache_destroy(dev_priv->objects); kmem_cache_destroy(dev_priv->objects);
pci_dev_put(dev_priv->bridge_dev); pci_dev_put(dev_priv->bridge_dev);
kfree(dev_priv); kfree(dev_priv);
......
...@@ -443,6 +443,34 @@ static const struct pci_device_id pciidlist[] = { /* aka */ ...@@ -443,6 +443,34 @@ static const struct pci_device_id pciidlist[] = { /* aka */
MODULE_DEVICE_TABLE(pci, pciidlist); 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) void intel_detect_pch(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -503,6 +531,8 @@ void intel_detect_pch(struct drm_device *dev) ...@@ -503,6 +531,8 @@ void intel_detect_pch(struct drm_device *dev)
dev_priv->pch_type = PCH_SPT; dev_priv->pch_type = PCH_SPT;
DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
WARN_ON(!IS_SKYLAKE(dev)); WARN_ON(!IS_SKYLAKE(dev));
} else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) {
dev_priv->pch_type = intel_virt_detect_pch(dev);
} else } else
continue; continue;
...@@ -608,6 +638,8 @@ static int i915_drm_suspend(struct drm_device *dev) ...@@ -608,6 +638,8 @@ static int i915_drm_suspend(struct drm_device *dev)
return error; return error;
} }
intel_guc_suspend(dev);
intel_suspend_gt_powersave(dev); intel_suspend_gt_powersave(dev);
/* /*
...@@ -737,6 +769,8 @@ static int i915_drm_resume(struct drm_device *dev) ...@@ -737,6 +769,8 @@ static int i915_drm_resume(struct drm_device *dev)
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
intel_guc_resume(dev);
intel_modeset_init_hw(dev); intel_modeset_init_hw(dev);
spin_lock_irq(&dev_priv->irq_lock); spin_lock_irq(&dev_priv->irq_lock);
...@@ -1021,12 +1055,6 @@ static int skl_suspend_complete(struct drm_i915_private *dev_priv) ...@@ -1021,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 */ /* 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); skl_uninit_cdclk(dev_priv);
return 0; return 0;
...@@ -1476,6 +1504,8 @@ static int intel_runtime_suspend(struct device *device) ...@@ -1476,6 +1504,8 @@ static int intel_runtime_suspend(struct device *device)
i915_gem_release_all_mmaps(dev_priv); i915_gem_release_all_mmaps(dev_priv);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
intel_guc_suspend(dev);
intel_suspend_gt_powersave(dev); intel_suspend_gt_powersave(dev);
intel_runtime_pm_disable_interrupts(dev_priv); intel_runtime_pm_disable_interrupts(dev_priv);
...@@ -1535,6 +1565,8 @@ static int intel_runtime_resume(struct device *device) ...@@ -1535,6 +1565,8 @@ static int intel_runtime_resume(struct device *device)
intel_opregion_notify_adapter(dev, PCI_D0); intel_opregion_notify_adapter(dev, PCI_D0);
dev_priv->pm.suspended = false; dev_priv->pm.suspended = false;
intel_guc_resume(dev);
if (IS_GEN6(dev_priv)) if (IS_GEN6(dev_priv))
intel_init_pch_refclk(dev); intel_init_pch_refclk(dev);
......
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#define DRIVER_NAME "i915" #define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics" #define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20150928" #define DRIVER_DATE "20151010"
#undef WARN_ON #undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */ /* Many gcc seem to no see through this and fall over :( */
...@@ -131,17 +131,17 @@ enum transcoder { ...@@ -131,17 +131,17 @@ enum transcoder {
#define transcoder_name(t) ((t) + 'A') #define transcoder_name(t) ((t) + 'A')
/* /*
* This is the maximum (across all platforms) number of planes (primary + * I915_MAX_PLANES in the enum below is the maximum (across all platforms)
* sprites) that can be active at the same time on one pipe. * 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
* This value doesn't count the cursor plane. * between the topmost sprite plane and the cursor plane.
*/ */
#define I915_MAX_PLANES 4
enum plane { enum plane {
PLANE_A = 0, PLANE_A = 0,
PLANE_B, PLANE_B,
PLANE_C, PLANE_C,
PLANE_CURSOR,
I915_MAX_PLANES,
}; };
#define plane_name(p) ((p) + 'A') #define plane_name(p) ((p) + 'A')
...@@ -628,10 +628,6 @@ struct drm_i915_display_funcs { ...@@ -628,10 +628,6 @@ struct drm_i915_display_funcs {
struct dpll *match_clock, struct dpll *match_clock,
struct dpll *best_clock); struct dpll *best_clock);
void (*update_wm)(struct drm_crtc *crtc); void (*update_wm)(struct drm_crtc *crtc);
void (*update_sprite_wm)(struct drm_plane *plane,
struct drm_crtc *crtc,
uint32_t sprite_width, uint32_t sprite_height,
int pixel_size, bool enable, bool scaled);
int (*modeset_calc_cdclk)(struct drm_atomic_state *state); int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
void (*modeset_commit_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
/* Returns the active state of the crtc, and if the crtc is active, /* Returns the active state of the crtc, and if the crtc is active,
...@@ -646,7 +642,7 @@ struct drm_i915_display_funcs { ...@@ -646,7 +642,7 @@ struct drm_i915_display_funcs {
void (*crtc_disable)(struct drm_crtc *crtc); void (*crtc_disable)(struct drm_crtc *crtc);
void (*audio_codec_enable)(struct drm_connector *connector, void (*audio_codec_enable)(struct drm_connector *connector,
struct intel_encoder *encoder, 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 (*audio_codec_disable)(struct intel_encoder *encoder);
void (*fdi_link_train)(struct drm_crtc *crtc); void (*fdi_link_train)(struct drm_crtc *crtc);
void (*init_clock_gating)(struct drm_device *dev); void (*init_clock_gating)(struct drm_device *dev);
...@@ -664,15 +660,6 @@ struct drm_i915_display_funcs { ...@@ -664,15 +660,6 @@ struct drm_i915_display_funcs {
/* render clock increase/decrease */ /* render clock increase/decrease */
/* display clock increase/decrease */ /* display clock increase/decrease */
/* pll 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);
uint32_t (*backlight_hz_to_pwm)(struct intel_connector *connector,
uint32_t hz);
}; };
enum forcewake_domain_id { enum forcewake_domain_id {
...@@ -1146,7 +1133,6 @@ struct intel_gen6_power_mgmt { ...@@ -1146,7 +1133,6 @@ struct intel_gen6_power_mgmt {
u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */ u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */
u8 rp1_freq; /* "less than" RP0 power/freqency */ u8 rp1_freq; /* "less than" RP0 power/freqency */
u8 rp0_freq; /* Non-overclocked max frequency. */ u8 rp0_freq; /* Non-overclocked max frequency. */
u32 cz_freq;
u8 up_threshold; /* Current %busy required to uplock */ u8 up_threshold; /* Current %busy required to uplock */
u8 down_threshold; /* Current %busy required to downclock */ u8 down_threshold; /* Current %busy required to downclock */
...@@ -1588,8 +1574,7 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1, ...@@ -1588,8 +1574,7 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
struct skl_ddb_allocation { struct skl_ddb_allocation {
struct skl_ddb_entry pipe[I915_MAX_PIPES]; 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 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 y_plane[I915_MAX_PIPES][I915_MAX_PLANES];
struct skl_ddb_entry cursor[I915_MAX_PIPES];
}; };
struct skl_wm_values { struct skl_wm_values {
...@@ -1597,18 +1582,13 @@ struct skl_wm_values { ...@@ -1597,18 +1582,13 @@ struct skl_wm_values {
struct skl_ddb_allocation ddb; struct skl_ddb_allocation ddb;
uint32_t wm_linetime[I915_MAX_PIPES]; uint32_t wm_linetime[I915_MAX_PIPES];
uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8]; 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 plane_trans[I915_MAX_PIPES][I915_MAX_PLANES];
uint32_t cursor_trans[I915_MAX_PIPES];
}; };
struct skl_wm_level { struct skl_wm_level {
bool plane_en[I915_MAX_PLANES]; bool plane_en[I915_MAX_PLANES];
bool cursor_en;
uint16_t plane_res_b[I915_MAX_PLANES]; uint16_t plane_res_b[I915_MAX_PLANES];
uint8_t plane_res_l[I915_MAX_PLANES]; uint8_t plane_res_l[I915_MAX_PLANES];
uint16_t cursor_res_b;
uint8_t cursor_res_l;
}; };
/* /*
...@@ -1809,6 +1789,7 @@ struct drm_i915_private { ...@@ -1809,6 +1789,7 @@ struct drm_i915_private {
unsigned int cdclk_freq, max_cdclk_freq; unsigned int cdclk_freq, max_cdclk_freq;
unsigned int max_dotclk_freq; unsigned int max_dotclk_freq;
unsigned int hpll_freq; unsigned int hpll_freq;
unsigned int czclk_freq;
/** /**
* wq - Driver workqueue for GEM. * wq - Driver workqueue for GEM.
...@@ -1897,6 +1878,11 @@ struct drm_i915_private { ...@@ -1897,6 +1878,11 @@ struct drm_i915_private {
/* hda/i915 audio component */ /* hda/i915 audio component */
struct i915_audio_component *audio_component; struct i915_audio_component *audio_component;
bool audio_component_registered; bool audio_component_registered;
/**
* av_mutex - mutex for audio/video sync
*
*/
struct mutex av_mutex;
uint32_t hw_context_size; uint32_t hw_context_size;
struct list_head context_list; struct list_head context_list;
...@@ -1959,6 +1945,9 @@ struct drm_i915_private { ...@@ -1959,6 +1945,9 @@ struct drm_i915_private {
bool edp_low_vswing; 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 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place. * will be rejected. Instead look for a better place.
...@@ -2607,6 +2596,7 @@ struct drm_i915_cmd_table { ...@@ -2607,6 +2596,7 @@ struct drm_i915_cmd_table {
#define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00 #define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00
#define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100 #define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100
#define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00 #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 INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type)
#define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT) #define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT)
...@@ -2824,6 +2814,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma); ...@@ -2824,6 +2814,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_OFFSET_BIAS (1<<3) #define PIN_OFFSET_BIAS (1<<3)
#define PIN_USER (1<<4) #define PIN_USER (1<<4)
#define PIN_UPDATE (1<<5) #define PIN_UPDATE (1<<5)
#define PIN_ZONE_4G (1<<6)
#define PIN_HIGH (1<<7)
#define PIN_OFFSET_MASK (~4095) #define PIN_OFFSET_MASK (~4095)
int __must_check int __must_check
i915_gem_object_pin(struct drm_i915_gem_object *obj, i915_gem_object_pin(struct drm_i915_gem_object *obj,
...@@ -2839,6 +2831,11 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, ...@@ -2839,6 +2831,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, int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags); u32 flags);
int __must_check i915_vma_unbind(struct i915_vma *vma); 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); 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_all_mmaps(struct drm_i915_private *dev_priv);
void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
...@@ -3167,7 +3164,6 @@ int __must_check i915_gem_evict_something(struct drm_device *dev, ...@@ -3167,7 +3164,6 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
unsigned long end, unsigned long end,
unsigned flags); unsigned flags);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); 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 */ /* belongs in i915_gem_gtt.h */
static inline void i915_gem_chipset_flush(struct drm_device *dev) static inline void i915_gem_chipset_flush(struct drm_device *dev)
...@@ -3198,11 +3194,12 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, ...@@ -3198,11 +3194,12 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
/* i915_gem_shrinker.c */ /* i915_gem_shrinker.c */
unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
long target, unsigned long target,
unsigned flags); unsigned flags);
#define I915_SHRINK_PURGEABLE 0x1 #define I915_SHRINK_PURGEABLE 0x1
#define I915_SHRINK_UNBOUND 0x2 #define I915_SHRINK_UNBOUND 0x2
#define I915_SHRINK_BOUND 0x4 #define I915_SHRINK_BOUND 0x4
#define I915_SHRINK_ACTIVE 0x8
unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv); unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
void i915_gem_shrinker_init(struct drm_i915_private *dev_priv); void i915_gem_shrinker_init(struct drm_i915_private *dev_priv);
......
...@@ -3208,7 +3208,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) ...@@ -3208,7 +3208,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
old_write_domain); 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_gem_object *obj = vma->obj;
struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
...@@ -3227,9 +3227,11 @@ int i915_vma_unbind(struct i915_vma *vma) ...@@ -3227,9 +3227,11 @@ int i915_vma_unbind(struct i915_vma *vma)
BUG_ON(obj->pages == NULL); BUG_ON(obj->pages == NULL);
if (wait) {
ret = i915_gem_object_wait_rendering(obj, false); ret = i915_gem_object_wait_rendering(obj, false);
if (ret) if (ret)
return ret; return ret;
}
if (i915_is_ggtt(vma->vm) && if (i915_is_ggtt(vma->vm) &&
vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) { vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
...@@ -3274,6 +3276,16 @@ int i915_vma_unbind(struct i915_vma *vma) ...@@ -3274,6 +3276,16 @@ int i915_vma_unbind(struct i915_vma *vma)
return 0; 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) int i915_gpu_idle(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -3354,11 +3366,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, ...@@ -3354,11 +3366,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
struct drm_device *dev = obj->base.dev; struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 fence_alignment, unfenced_alignment; u32 fence_alignment, unfenced_alignment;
u32 search_flag, alloc_flag;
u64 start, end;
u64 size, fence_size; u64 size, fence_size;
u64 start =
flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
u64 end =
flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total;
struct i915_vma *vma; struct i915_vma *vma;
int ret; int ret;
...@@ -3398,6 +3408,13 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, ...@@ -3398,6 +3408,13 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
size = flags & PIN_MAPPABLE ? fence_size : obj->base.size; 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) if (alignment == 0)
alignment = flags & PIN_MAPPABLE ? fence_alignment : alignment = flags & PIN_MAPPABLE ? fence_alignment :
unfenced_alignment; unfenced_alignment;
...@@ -3433,13 +3450,21 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, ...@@ -3433,13 +3450,21 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (IS_ERR(vma)) if (IS_ERR(vma))
goto err_unpin; 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: search_free:
ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
size, alignment, size, alignment,
obj->cache_level, obj->cache_level,
start, end, start, end,
DRM_MM_SEARCH_DEFAULT, search_flag,
DRM_MM_CREATE_DEFAULT); alloc_flag);
if (ret) { if (ret) {
ret = i915_gem_evict_something(dev, vm, size, alignment, ret = i915_gem_evict_something(dev, vm, size, alignment,
obj->cache_level, obj->cache_level,
...@@ -4533,22 +4558,6 @@ void i915_gem_init_swizzling(struct drm_device *dev) ...@@ -4533,22 +4558,6 @@ void i915_gem_init_swizzling(struct drm_device *dev)
BUG(); 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) static void init_unused_ring(struct drm_device *dev, u32 base)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -4591,7 +4600,7 @@ int i915_gem_init_rings(struct drm_device *dev) ...@@ -4591,7 +4600,7 @@ int i915_gem_init_rings(struct drm_device *dev)
goto cleanup_render_ring; goto cleanup_render_ring;
} }
if (intel_enable_blt(dev)) { if (HAS_BLT(dev)) {
ret = intel_init_blt_ring_buffer(dev); ret = intel_init_blt_ring_buffer(dev);
if (ret) if (ret)
goto cleanup_bsd_ring; goto cleanup_bsd_ring;
......
...@@ -133,6 +133,23 @@ static int get_context_size(struct drm_device *dev) ...@@ -133,6 +133,23 @@ static int get_context_size(struct drm_device *dev)
return ret; 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) void i915_gem_context_free(struct kref *ctx_ref)
{ {
struct intel_context *ctx = container_of(ctx_ref, typeof(*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) ...@@ -142,6 +159,13 @@ void i915_gem_context_free(struct kref *ctx_ref)
if (i915.enable_execlists) if (i915.enable_execlists)
intel_lr_context_free(ctx); 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); i915_ppgtt_put(ctx->ppgtt);
if (ctx->legacy_hw_ctx.rcs_state) if (ctx->legacy_hw_ctx.rcs_state)
......
...@@ -237,48 +237,3 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle) ...@@ -237,48 +237,3 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
return 0; 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;
}
...@@ -590,10 +590,17 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma, ...@@ -590,10 +590,17 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
flags |= PIN_GLOBAL; flags |= PIN_GLOBAL;
if (!drm_mm_node_allocated(&vma->node)) { 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) if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
flags |= PIN_GLOBAL | PIN_MAPPABLE; flags |= PIN_GLOBAL | PIN_MAPPABLE;
if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS) if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_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); ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
...@@ -671,6 +678,10 @@ eb_vma_misplaced(struct i915_vma *vma) ...@@ -671,6 +678,10 @@ eb_vma_misplaced(struct i915_vma *vma)
if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable) if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
return !only_mappable_for_reloc(entry->flags); 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; return false;
} }
...@@ -934,7 +945,21 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) ...@@ -934,7 +945,21 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS)
return false; 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 static int
...@@ -1098,47 +1123,6 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, ...@@ -1098,47 +1123,6 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
return 0; 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* static struct drm_i915_gem_object*
i915_gem_execbuffer_parse(struct intel_engine_cs *ring, i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
struct drm_i915_gem_exec_object2 *shadow_exec_entry, struct drm_i915_gem_exec_object2 *shadow_exec_entry,
...@@ -1197,65 +1181,21 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, ...@@ -1197,65 +1181,21 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
struct drm_i915_gem_execbuffer2 *args, struct drm_i915_gem_execbuffer2 *args,
struct list_head *vmas) struct list_head *vmas)
{ {
struct drm_clip_rect *cliprects = NULL;
struct drm_device *dev = params->dev; struct drm_device *dev = params->dev;
struct intel_engine_cs *ring = params->ring; struct intel_engine_cs *ring = params->ring;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u64 exec_start, exec_len; u64 exec_start, exec_len;
int instp_mode; int instp_mode;
u32 instp_mask; u32 instp_mask;
int i, ret = 0; int ret;
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;
}
}
ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas); ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas);
if (ret) if (ret)
goto error; return ret;
ret = i915_switch_context(params->request); ret = i915_switch_context(params->request);
if (ret) if (ret)
goto error; return ret;
WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<<ring->id), WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
"%s didn't clear reload\n", ring->name); "%s didn't clear reload\n", ring->name);
...@@ -1268,22 +1208,19 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, ...@@ -1268,22 +1208,19 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
case I915_EXEC_CONSTANTS_REL_SURFACE: case I915_EXEC_CONSTANTS_REL_SURFACE:
if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) { if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
DRM_DEBUG("non-0 rel constants mode on non-RCS\n"); DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
if (instp_mode != dev_priv->relative_constants_mode) { if (instp_mode != dev_priv->relative_constants_mode) {
if (INTEL_INFO(dev)->gen < 4) { if (INTEL_INFO(dev)->gen < 4) {
DRM_DEBUG("no rel constants on pre-gen4\n"); DRM_DEBUG("no rel constants on pre-gen4\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
if (INTEL_INFO(dev)->gen > 5 && if (INTEL_INFO(dev)->gen > 5 &&
instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) { instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
DRM_DEBUG("rel surface constants mode invalid on gen5+\n"); DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
ret = -EINVAL; return -EINVAL;
goto error;
} }
/* The HW changed the meaning on this bit on gen6 */ /* The HW changed the meaning on this bit on gen6 */
...@@ -1293,15 +1230,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, ...@@ -1293,15 +1230,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
break; break;
default: default:
DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode); DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
ret = -EINVAL; return -EINVAL;
goto error;
} }
if (ring == &dev_priv->ring[RCS] && 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); ret = intel_ring_begin(params->request, 4);
if (ret) if (ret)
goto error; return ret;
intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_NOOP);
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
...@@ -1315,42 +1251,25 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, ...@@ -1315,42 +1251,25 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
if (args->flags & I915_EXEC_GEN7_SOL_RESET) { if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
ret = i915_reset_gen7_sol_offsets(dev, params->request); ret = i915_reset_gen7_sol_offsets(dev, params->request);
if (ret) if (ret)
goto error; return ret;
} }
exec_len = args->batch_len; exec_len = args->batch_len;
exec_start = params->batch_obj_vm_offset + exec_start = params->batch_obj_vm_offset +
params->args_batch_start_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, ret = ring->dispatch_execbuffer(params->request,
exec_start, exec_len, exec_start, exec_len,
params->dispatch_flags); params->dispatch_flags);
if (ret) if (ret)
return ret; return ret;
}
trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags);
i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_move_to_active(vmas, params->request);
i915_gem_execbuffer_retire_commands(params); i915_gem_execbuffer_retire_commands(params);
error: return 0;
kfree(cliprects);
return ret;
} }
/** /**
......
...@@ -59,19 +59,19 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, ...@@ -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_gem_object *obj)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int fence_reg; int fence_reg_lo, fence_reg_hi;
int fence_pitch_shift; int fence_pitch_shift;
if (INTEL_INFO(dev)->gen >= 6) { if (INTEL_INFO(dev)->gen >= 6) {
fence_reg = FENCE_REG_SANDYBRIDGE_0; fence_reg_lo = FENCE_REG_GEN6_LO(reg);
fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; fence_reg_hi = FENCE_REG_GEN6_HI(reg);
fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT;
} else { } 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_pitch_shift = I965_FENCE_PITCH_SHIFT;
} }
fence_reg += reg * 8;
/* To w/a incoherency with non-atomic 64-bit register updates, /* To w/a incoherency with non-atomic 64-bit register updates,
* we split the 64-bit update into two 32-bit writes. In order * we split the 64-bit update into two 32-bit writes. In order
* for a partial fence not to be evaluated between writes, we * 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, ...@@ -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 * For extra levels of paranoia, we make sure each step lands
* before applying the next step. * before applying the next step.
*/ */
I915_WRITE(fence_reg, 0); I915_WRITE(fence_reg_lo, 0);
POSTING_READ(fence_reg); POSTING_READ(fence_reg_lo);
if (obj) { if (obj) {
u32 size = i915_gem_obj_ggtt_size(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, ...@@ -103,14 +103,14 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= 1 << I965_FENCE_TILING_Y_SHIFT;
val |= I965_FENCE_REG_VALID; val |= I965_FENCE_REG_VALID;
I915_WRITE(fence_reg + 4, val >> 32); I915_WRITE(fence_reg_hi, val >> 32);
POSTING_READ(fence_reg + 4); POSTING_READ(fence_reg_hi);
I915_WRITE(fence_reg + 0, val); I915_WRITE(fence_reg_lo, val);
POSTING_READ(fence_reg); POSTING_READ(fence_reg_lo);
} else { } else {
I915_WRITE(fence_reg + 4, 0); I915_WRITE(fence_reg_hi, 0);
POSTING_READ(fence_reg + 4); POSTING_READ(fence_reg_hi);
} }
} }
...@@ -149,13 +149,8 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg, ...@@ -149,13 +149,8 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
} else } else
val = 0; val = 0;
if (reg < 8) I915_WRITE(FENCE_REG(reg), val);
reg = FENCE_REG_830_0 + reg * 4; POSTING_READ(FENCE_REG(reg));
else
reg = FENCE_REG_945_8 + (reg - 8) * 4;
I915_WRITE(reg, val);
POSTING_READ(reg);
} }
static void i830_write_fence_reg(struct drm_device *dev, int reg, static void i830_write_fence_reg(struct drm_device *dev, int reg,
...@@ -186,8 +181,8 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, ...@@ -186,8 +181,8 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
} else } else
val = 0; val = 0;
I915_WRITE(FENCE_REG_830_0 + reg * 4, val); I915_WRITE(FENCE_REG(reg), val);
POSTING_READ(FENCE_REG_830_0 + reg * 4); POSTING_READ(FENCE_REG(reg));
} }
inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
......
...@@ -2889,8 +2889,8 @@ static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv) ...@@ -2889,8 +2889,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 /* XXX: spec defines this as 2 distinct registers. It's unclear if a 64b
* write would work. */ * write would work. */
I915_WRITE(GEN8_PRIVATE_PAT, pat); I915_WRITE(GEN8_PRIVATE_PAT_LO, pat);
I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32);
} }
static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
...@@ -2924,8 +2924,8 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) ...@@ -2924,8 +2924,8 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
GEN8_PPAT(6, CHV_PPAT_SNOOP) | GEN8_PPAT(6, CHV_PPAT_SNOOP) |
GEN8_PPAT(7, CHV_PPAT_SNOOP); GEN8_PPAT(7, CHV_PPAT_SNOOP);
I915_WRITE(GEN8_PRIVATE_PAT, pat); I915_WRITE(GEN8_PRIVATE_PAT_LO, pat);
I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32); I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32);
} }
static int gen8_gmch_probe(struct drm_device *dev, static int gen8_gmch_probe(struct drm_device *dev,
......
...@@ -394,7 +394,8 @@ struct i915_hw_ppgtt { ...@@ -394,7 +394,8 @@ struct i915_hw_ppgtt {
*/ */
#define gen6_for_each_pde(pt, pd, start, length, temp, iter) \ #define gen6_for_each_pde(pt, pd, start, length, temp, iter) \
for (iter = gen6_pde_index(start); \ 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++, \ iter++, \
temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \ temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \
temp = min_t(unsigned, temp, length), \ temp = min_t(unsigned, temp, length), \
...@@ -459,7 +460,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) ...@@ -459,7 +460,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
*/ */
#define gen8_for_each_pde(pt, pd, start, length, temp, iter) \ #define gen8_for_each_pde(pt, pd, start, length, temp, iter) \
for (iter = gen8_pde_index(start); \ 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++, \ iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \ temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \
temp = min(temp, length), \ temp = min(temp, length), \
...@@ -467,8 +469,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) ...@@ -467,8 +469,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \ #define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
for (iter = gen8_pdpe_index(start); \ for (iter = gen8_pdpe_index(start); \
pd = (pdp)->page_directory[iter], \ length > 0 && (iter < I915_PDPES_PER_PDP(dev)) ? \
length > 0 && (iter < I915_PDPES_PER_PDP(dev)); \ (pd = (pdp)->page_directory[iter]), 1 : 0; \
iter++, \ iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \ temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \
temp = min(temp, length), \ temp = min(temp, length), \
...@@ -476,8 +478,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr) ...@@ -476,8 +478,8 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
#define gen8_for_each_pml4e(pdp, pml4, start, length, temp, iter) \ #define gen8_for_each_pml4e(pdp, pml4, start, length, temp, iter) \
for (iter = gen8_pml4e_index(start); \ for (iter = gen8_pml4e_index(start); \
pdp = (pml4)->pdps[iter], \ length > 0 && iter < GEN8_PML4ES_PER_PML4 ? \
length > 0 && iter < GEN8_PML4ES_PER_PML4; \ (pdp = (pml4)->pdps[iter]), 1 : 0; \
iter++, \ iter++, \
temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT) - start, \ temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT) - start, \
temp = min(temp, length), \ temp = min(temp, length), \
......
...@@ -73,7 +73,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) ...@@ -73,7 +73,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
*/ */
unsigned long unsigned long
i915_gem_shrink(struct drm_i915_private *dev_priv, i915_gem_shrink(struct drm_i915_private *dev_priv,
long target, unsigned flags) unsigned long target, unsigned flags)
{ {
const struct { const struct {
struct list_head *list; struct list_head *list;
...@@ -85,6 +85,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -85,6 +85,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
}, *phase; }, *phase;
unsigned long count = 0; 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 * As we may completely rewrite the (un)bound list whilst unbinding
* (due to retiring requests) we have to strictly process only * (due to retiring requests) we have to strictly process only
...@@ -123,6 +126,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -123,6 +126,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
obj->madv != I915_MADV_DONTNEED) obj->madv != I915_MADV_DONTNEED)
continue; continue;
if ((flags & I915_SHRINK_ACTIVE) == 0 && obj->active)
continue;
drm_gem_object_reference(&obj->base); drm_gem_object_reference(&obj->base);
/* For the unbound phase, this should be a no-op! */ /* For the unbound phase, this should be a no-op! */
...@@ -139,11 +145,13 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -139,11 +145,13 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
list_splice(&still_in_list, phase->list); list_splice(&still_in_list, phase->list);
} }
i915_gem_retire_requests(dev_priv->dev);
return count; return count;
} }
/** /**
* i915_gem_shrink - Shrink buffer object caches completely * i915_gem_shrink_all - Shrink buffer object caches completely
* @dev_priv: i915 device * @dev_priv: i915 device
* *
* This is a simple wraper around i915_gem_shrink() to aggressively shrink all * This is a simple wraper around i915_gem_shrink() to aggressively shrink all
...@@ -158,9 +166,10 @@ i915_gem_shrink(struct drm_i915_private *dev_priv, ...@@ -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) 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, -1UL,
return i915_gem_shrink(dev_priv, LONG_MAX, I915_SHRINK_BOUND |
I915_SHRINK_BOUND | I915_SHRINK_UNBOUND); I915_SHRINK_UNBOUND |
I915_SHRINK_ACTIVE);
} }
static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) 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) ...@@ -213,7 +222,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
count += obj->base.size >> PAGE_SHIFT; count += obj->base.size >> PAGE_SHIFT;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { 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; count += obj->base.size >> PAGE_SHIFT;
} }
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include <drm/i915_drm.h> #include <drm/i915_drm.h>
#include "i915_drv.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 * 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 * use of the integrated graphics. This memory is no longer available for
...@@ -51,6 +54,11 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv, ...@@ -51,6 +54,11 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
if (!drm_mm_initialized(&dev_priv->mm.stolen)) if (!drm_mm_initialized(&dev_priv->mm.stolen))
return -ENODEV; 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); mutex_lock(&dev_priv->mm.stolen_lock);
ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size, ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size,
alignment, start, end, alignment, start, end,
...@@ -86,24 +94,91 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) ...@@ -86,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 /* Almost universally we can find the Graphics Base of Stolen Memory
* at offset 0x5c in the igfx configuration space. On a few (desktop) * at offset 0x5c in the igfx configuration space. On a few (desktop)
* machines this is also mirrored in the bridge device at different * machines this is also mirrored in the bridge device at different
* locations, or in the MCHBAR. On gen2, the layout is again slightly * locations, or in the MCHBAR.
* different with the Graphics Segment immediately following Top of *
* Memory (or Top of Usable DRAM). Note it appears that TOUD is only * On 865 we just check the TOUD register.
* reported by 865g, so we just use the top of memory as determined *
* by the e820 probe. * 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; base = 0;
if (INTEL_INFO(dev)->gen >= 3) { if (INTEL_INFO(dev)->gen >= 3) {
/* Read Graphics Base of Stolen Memory directly */ /* Read Graphics Base of Stolen Memory directly */
pci_read_config_dword(dev->pdev, 0x5c, &base); pci_read_config_dword(dev->pdev, 0x5c, &base);
base &= ~((1<<20) - 1); base &= ~((1<<20) - 1);
} else { /* GEN2 */ } else if (IS_I865G(dev)) {
#if 0 u16 toud = 0;
/* Stolen is immediately above Top of Memory */
base = max_low_pfn_mapped << PAGE_SHIFT; /*
#endif * 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) if (base == 0)
...@@ -393,7 +468,17 @@ int i915_gem_init_stolen(struct drm_device *dev) ...@@ -393,7 +468,17 @@ int i915_gem_init_stolen(struct drm_device *dev)
dev_priv->gtt.stolen_usable_size = dev_priv->gtt.stolen_size - dev_priv->gtt.stolen_usable_size = dev_priv->gtt.stolen_size -
reserved_total; reserved_total;
/* Basic memrange allocator for stolen space */ /*
* 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); drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_usable_size);
return 0; return 0;
......
...@@ -50,7 +50,6 @@ struct i915_mmu_notifier { ...@@ -50,7 +50,6 @@ struct i915_mmu_notifier {
struct mmu_notifier mn; struct mmu_notifier mn;
struct rb_root objects; struct rb_root objects;
struct list_head linear; struct list_head linear;
unsigned long serial;
bool has_linear; bool has_linear;
}; };
...@@ -59,13 +58,16 @@ struct i915_mmu_object { ...@@ -59,13 +58,16 @@ struct i915_mmu_object {
struct interval_tree_node it; struct interval_tree_node it;
struct list_head link; struct list_head link;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct work_struct work;
bool active;
bool is_linear; 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; struct drm_device *dev = obj->base.dev;
unsigned long end;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
/* Cancel any active worker and force us to re-evaluate gup */ /* 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) ...@@ -88,45 +90,28 @@ static unsigned long cancel_userptr(struct drm_i915_gem_object *obj)
dev_priv->mm.interruptible = was_interruptible; dev_priv->mm.interruptible = was_interruptible;
} }
end = obj->userptr.ptr + obj->base.size;
drm_gem_object_unreference(&obj->base); drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return end;
} }
static void *invalidate_range__linear(struct i915_mmu_notifier *mn, static unsigned long cancel_userptr(struct i915_mmu_object *mo)
struct mm_struct *mm,
unsigned long start,
unsigned long end)
{ {
struct i915_mmu_object *mo; unsigned long end = mo->obj->userptr.ptr + mo->obj->base.size;
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) /* The mmu_object is released late when destroying the
continue; * GEM object so it is entirely possible to gain a
* reference on an object in the process of being freed
obj = mo->obj; * since our serialisation is via the spinlock and not
* the struct_mutex - and consequently use it after it
if (!kref_get_unless_zero(&obj->base.refcount)) * is freed and then double free it.
continue; */
if (mo->active && kref_get_unless_zero(&mo->obj->base.refcount)) {
spin_unlock(&mn->lock); schedule_work(&mo->work);
/* only schedule one work packet to avoid the refleak */
cancel_userptr(obj); mo->active = false;
spin_lock(&mn->lock);
if (serial != mn->serial)
goto restart;
} }
return NULL; return end;
} }
static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, 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, ...@@ -134,46 +119,32 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
unsigned long start, unsigned long start,
unsigned long end) unsigned long end)
{ {
struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn); struct i915_mmu_notifier *mn =
struct interval_tree_node *it = NULL; container_of(_mn, struct i915_mmu_notifier, mn);
unsigned long next = start; struct i915_mmu_object *mo;
unsigned long serial = 0;
end--; /* interval ranges are inclusive, but invalidate range is exclusive */ /* interval ranges are inclusive, but invalidate range is exclusive */
while (next < end) { end--;
struct drm_i915_gem_object *obj = NULL;
spin_lock(&mn->lock); spin_lock(&mn->lock);
if (mn->has_linear) if (mn->has_linear) {
it = invalidate_range__linear(mn, mm, start, end); list_for_each_entry(mo, &mn->linear, link) {
else if (serial == mn->serial) if (mo->it.last < start || mo->it.start > end)
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;
continue; continue;
}
serial = mn->serial; cancel_userptr(mo);
} }
spin_unlock(&mn->lock); } else {
if (obj == NULL) struct interval_tree_node *it;
return;
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 = { static const struct mmu_notifier_ops i915_gem_userptr_notifier = {
...@@ -193,7 +164,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) ...@@ -193,7 +164,6 @@ i915_mmu_notifier_create(struct mm_struct *mm)
spin_lock_init(&mn->lock); spin_lock_init(&mn->lock);
mn->mn.ops = &i915_gem_userptr_notifier; mn->mn.ops = &i915_gem_userptr_notifier;
mn->objects = RB_ROOT; mn->objects = RB_ROOT;
mn->serial = 1;
INIT_LIST_HEAD(&mn->linear); INIT_LIST_HEAD(&mn->linear);
mn->has_linear = false; mn->has_linear = false;
...@@ -207,12 +177,6 @@ i915_mmu_notifier_create(struct mm_struct *mm) ...@@ -207,12 +177,6 @@ i915_mmu_notifier_create(struct mm_struct *mm)
return mn; return mn;
} }
static void __i915_mmu_notifier_update_serial(struct i915_mmu_notifier *mn)
{
if (++mn->serial == 0)
mn->serial = 1;
}
static int static int
i915_mmu_notifier_add(struct drm_device *dev, i915_mmu_notifier_add(struct drm_device *dev,
struct i915_mmu_notifier *mn, struct i915_mmu_notifier *mn,
...@@ -259,10 +223,9 @@ i915_mmu_notifier_add(struct drm_device *dev, ...@@ -259,10 +223,9 @@ i915_mmu_notifier_add(struct drm_device *dev,
} else } else
interval_tree_insert(&mo->it, &mn->objects); interval_tree_insert(&mo->it, &mn->objects);
if (ret == 0) { if (ret == 0)
list_add(&mo->link, &mn->linear); list_add(&mo->link, &mn->linear);
__i915_mmu_notifier_update_serial(mn);
}
spin_unlock(&mn->lock); spin_unlock(&mn->lock);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -290,7 +253,6 @@ i915_mmu_notifier_del(struct i915_mmu_notifier *mn, ...@@ -290,7 +253,6 @@ i915_mmu_notifier_del(struct i915_mmu_notifier *mn,
mn->has_linear = i915_mmu_notifier_has_linear(mn); mn->has_linear = i915_mmu_notifier_has_linear(mn);
else else
interval_tree_remove(&mo->it, &mn->objects); interval_tree_remove(&mo->it, &mn->objects);
__i915_mmu_notifier_update_serial(mn);
spin_unlock(&mn->lock); spin_unlock(&mn->lock);
} }
...@@ -357,6 +319,7 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, ...@@ -357,6 +319,7 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj,
mo->it.start = obj->userptr.ptr; mo->it.start = obj->userptr.ptr;
mo->it.last = mo->it.start + obj->base.size - 1; mo->it.last = mo->it.start + obj->base.size - 1;
mo->obj = obj; mo->obj = obj;
INIT_WORK(&mo->work, __cancel_userptr__worker);
ret = i915_mmu_notifier_add(obj->base.dev, mn, mo); ret = i915_mmu_notifier_add(obj->base.dev, mn, mo);
if (ret) { if (ret) {
...@@ -565,31 +528,65 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj, ...@@ -565,31 +528,65 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj,
return ret; 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 static void
__i915_gem_userptr_get_pages_worker(struct work_struct *_work) __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
{ {
struct get_pages_work *work = container_of(_work, typeof(*work), work); struct get_pages_work *work = container_of(_work, typeof(*work), work);
struct drm_i915_gem_object *obj = work->obj; struct drm_i915_gem_object *obj = work->obj;
struct drm_device *dev = obj->base.dev; 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; struct page **pvec;
int pinned, ret; int pinned, ret;
ret = -ENOMEM; ret = -ENOMEM;
pinned = 0; pinned = 0;
pvec = kmalloc(num_pages*sizeof(struct page *), pvec = kmalloc(npages*sizeof(struct page *),
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (pvec == NULL) if (pvec == NULL)
pvec = drm_malloc_ab(num_pages, sizeof(struct page *)); pvec = drm_malloc_ab(npages, sizeof(struct page *));
if (pvec != NULL) { if (pvec != NULL) {
struct mm_struct *mm = obj->userptr.mm->mm; struct mm_struct *mm = obj->userptr.mm->mm;
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
while (pinned < num_pages) { while (pinned < npages) {
ret = get_user_pages(work->task, mm, ret = get_user_pages(work->task, mm,
obj->userptr.ptr + pinned * PAGE_SIZE, obj->userptr.ptr + pinned * PAGE_SIZE,
num_pages - pinned, npages - pinned,
!obj->userptr.read_only, 0, !obj->userptr.read_only, 0,
pvec + pinned, NULL); pvec + pinned, NULL);
if (ret < 0) if (ret < 0)
...@@ -601,20 +598,22 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) ...@@ -601,20 +598,22 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
} }
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (obj->userptr.work != &work->work) { if (obj->userptr.work == &work->work) {
ret = 0; if (pinned == npages) {
} else if (pinned == num_pages) { ret = __i915_gem_userptr_set_pages(obj, pvec, npages);
ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
if (ret == 0) { if (ret == 0) {
list_add_tail(&obj->global_list, &to_i915(dev)->mm.unbound_list); list_add_tail(&obj->global_list,
&to_i915(dev)->mm.unbound_list);
obj->get_page.sg = obj->pages->sgl; obj->get_page.sg = obj->pages->sgl;
obj->get_page.last = 0; obj->get_page.last = 0;
pinned = 0; pinned = 0;
} }
} }
obj->userptr.work = ERR_PTR(ret); obj->userptr.work = ERR_PTR(ret);
if (ret)
__i915_gem_userptr_set_active(obj, false);
}
obj->userptr.workers--; obj->userptr.workers--;
drm_gem_object_unreference(&obj->base); drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -627,48 +626,11 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) ...@@ -627,48 +626,11 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
} }
static int static int
i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj,
bool *active)
{ {
const int num_pages = obj->base.size >> PAGE_SHIFT; struct get_pages_work *work;
struct page **pvec;
int pinned, ret;
/* If userspace should engineer that these pages are replaced in
* the vma between us binding this page into the GTT and completion
* of rendering... Their loss. If they change the mapping of their
* pages they need to create a new bo to point to the new vma.
*
* However, that still leaves open the possibility of the vma
* being copied upon fork. Which falls under the same userspace
* synchronisation issue as a regular bo, except that this time
* the process may not be expecting that a particular piece of
* memory is tied to the GPU.
*
* Fortunately, we can hook into the mmu_notifier in order to
* discard the page references prior to anything nasty happening
* to the vma (discard or cloning) which should prevent the more
* egregious cases from causing harm.
*/
pvec = NULL;
pinned = 0;
if (obj->userptr.mm->mm == current->mm) {
pvec = kmalloc(num_pages*sizeof(struct page *),
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (pvec == NULL) {
pvec = drm_malloc_ab(num_pages, sizeof(struct page *));
if (pvec == NULL)
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 /* Spawn a worker so that we can acquire the
* user pages without holding our mutex. Access * user pages without holding our mutex. Access
* to the user pages requires mmap_sem, and we have * to the user pages requires mmap_sem, and we have
...@@ -688,13 +650,13 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) ...@@ -688,13 +650,13 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
* that error back to this function through * that error back to this function through
* obj->userptr.work = ERR_PTR. * obj->userptr.work = ERR_PTR.
*/ */
ret = -EAGAIN; if (obj->userptr.workers >= I915_GEM_USERPTR_MAX_WORKERS)
if (obj->userptr.work == NULL && return -EAGAIN;
obj->userptr.workers < I915_GEM_USERPTR_MAX_WORKERS) {
struct get_pages_work *work;
work = kmalloc(sizeof(*work), GFP_KERNEL); work = kmalloc(sizeof(*work), GFP_KERNEL);
if (work != NULL) { if (work == NULL)
return -ENOMEM;
obj->userptr.work = &work->work; obj->userptr.work = &work->work;
obj->userptr.workers++; obj->userptr.workers++;
...@@ -706,24 +668,78 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) ...@@ -706,24 +668,78 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
schedule_work(&work->work); schedule_work(&work->work);
} else
ret = -ENOMEM; *active = true;
} else { 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
* of rendering... Their loss. If they change the mapping of their
* pages they need to create a new bo to point to the new vma.
*
* However, that still leaves open the possibility of the vma
* being copied upon fork. Which falls under the same userspace
* synchronisation issue as a regular bo, except that this time
* the process may not be expecting that a particular piece of
* memory is tied to the GPU.
*
* Fortunately, we can hook into the mmu_notifier in order to
* discard the page references prior to anything nasty happening
* to the vma (discard or cloning) which should prevent the more
* egregious cases from causing harm.
*/
if (IS_ERR(obj->userptr.work)) { if (IS_ERR(obj->userptr.work)) {
/* active flag will have been dropped already by the worker */
ret = PTR_ERR(obj->userptr.work); ret = PTR_ERR(obj->userptr.work);
obj->userptr.work = NULL; obj->userptr.work = NULL;
return ret;
} }
} if (obj->userptr.work)
} /* active flag should still be held for the pending work */
} else { return -EAGAIN;
ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
if (ret == 0) { /* Let the mmu-notifier know that we have begun and need cancellation */
obj->userptr.work = NULL; ret = __i915_gem_userptr_set_active(obj, true);
if (ret)
return ret;
pvec = NULL;
pinned = 0; pinned = 0;
if (obj->userptr.mm->mm == current->mm) {
pvec = kmalloc(num_pages*sizeof(struct page *),
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (pvec == NULL) {
pvec = drm_malloc_ab(num_pages, sizeof(struct page *));
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);
}
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) {
__i915_gem_userptr_set_active(obj, active);
release_pages(pvec, pinned, 0); release_pages(pvec, pinned, 0);
}
drm_free_large(pvec); drm_free_large(pvec);
return ret; return ret;
} }
...@@ -734,6 +750,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj) ...@@ -734,6 +750,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
struct sg_page_iter sg_iter; struct sg_page_iter sg_iter;
BUG_ON(obj->userptr.work != NULL); BUG_ON(obj->userptr.work != NULL);
__i915_gem_userptr_set_active(obj, false);
if (obj->madv != I915_MADV_WILLNEED) if (obj->madv != I915_MADV_WILLNEED)
obj->dirty = 0; obj->dirty = 0;
......
...@@ -792,20 +792,15 @@ static void i915_gem_record_fences(struct drm_device *dev, ...@@ -792,20 +792,15 @@ static void i915_gem_record_fences(struct drm_device *dev,
int i; int i;
if (IS_GEN3(dev) || IS_GEN2(dev)) { 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++) for (i = 0; i < dev_priv->num_fence_regs; i++)
error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + error->fence[i] = I915_READ(FENCE_REG(i));
(i * 8)); } 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));
}
} }
...@@ -891,7 +886,7 @@ static void i915_record_ring_state(struct drm_device *dev, ...@@ -891,7 +886,7 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->faddr = I915_READ(DMA_FADD_I8XX); ering->faddr = I915_READ(DMA_FADD_I8XX);
ering->ipeir = I915_READ(IPEIR); ering->ipeir = I915_READ(IPEIR);
ering->ipehr = I915_READ(IPEHR); ering->ipehr = I915_READ(IPEHR);
ering->instdone = I915_READ(INSTDONE); ering->instdone = I915_READ(GEN2_INSTDONE);
} }
ering->waiting = waitqueue_active(&ring->irq_queue); ering->waiting = waitqueue_active(&ring->irq_queue);
...@@ -1393,12 +1388,12 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone) ...@@ -1393,12 +1388,12 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG); memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
if (IS_GEN2(dev) || IS_GEN3(dev)) 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)) { else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
instdone[0] = I915_READ(INSTDONE_I965); instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE));
instdone[1] = I915_READ(INSTDONE1); instdone[1] = I915_READ(GEN4_INSTDONE1);
} else if (INTEL_INFO(dev)->gen >= 7) { } 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[1] = I915_READ(GEN7_SC_INSTDONE);
instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE); instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
instdone[3] = I915_READ(GEN7_ROW_INSTDONE); instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
......
...@@ -37,10 +37,11 @@ ...@@ -37,10 +37,11 @@
#define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT) #define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT)
#define GS_MIA_SHIFT 16 #define GS_MIA_SHIFT 16
#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) #define GS_MIA_MASK (0x07 << GS_MIA_SHIFT)
#define GS_MIA_CORE_STATE (1 << GS_MIA_SHIFT)
#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) #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_LOW 0xc300
#define DMA_ADDR_0_HIGH 0xc304 #define DMA_ADDR_0_HIGH 0xc304
#define DMA_ADDR_1_LOW 0xc308 #define DMA_ADDR_1_LOW 0xc308
......
...@@ -155,12 +155,21 @@ static int host2guc_sample_forcewake(struct intel_guc *guc, ...@@ -155,12 +155,21 @@ static int host2guc_sample_forcewake(struct intel_guc *guc,
struct i915_guc_client *client) struct i915_guc_client *client)
{ {
struct drm_i915_private *dev_priv = guc_to_i915(guc); struct drm_i915_private *dev_priv = guc_to_i915(guc);
struct drm_device *dev = dev_priv->dev;
u32 data[2]; u32 data[2];
data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE; data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
data[1] = (intel_enable_rc6(dev_priv->dev)) ? 1 : 0; /* 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, 2); return host2guc_action(guc, data, ARRAY_SIZE(data));
} }
/* /*
...@@ -914,3 +923,53 @@ void i915_guc_submission_fini(struct drm_device *dev) ...@@ -914,3 +923,53 @@ void i915_guc_submission_fini(struct drm_device *dev)
gem_release_guc_obj(guc->ctx_pool_obj); gem_release_guc_obj(guc->ctx_pool_obj);
guc->ctx_pool_obj = NULL; 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));
}
...@@ -581,6 +581,7 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, ...@@ -581,6 +581,7 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
/** /**
* i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
* @dev: drm device
*/ */
static void i915_enable_asle_pipestat(struct drm_device *dev) static void i915_enable_asle_pipestat(struct drm_device *dev)
{ {
...@@ -997,12 +998,16 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv, ...@@ -997,12 +998,16 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv,
int threshold) int threshold)
{ {
u64 time, c0; u64 time, c0;
unsigned int mul = 100;
if (old->cz_clock == 0) if (old->cz_clock == 0)
return false; return false;
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
mul <<= 8;
time = now->cz_clock - old->cz_clock; 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 /* Workload can be split between render + media, e.g. SwapBuffers
* being blitted in X after being rendered in mesa. To account for * being blitted in X after being rendered in mesa. To account for
...@@ -1010,7 +1015,7 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv, ...@@ -1010,7 +1015,7 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv,
*/ */
c0 = now->render_c0 - old->render_c0; c0 = now->render_c0 - old->render_c0;
c0 += now->media_c0 - old->media_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; return c0 >= time;
} }
...@@ -2388,6 +2393,7 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv, ...@@ -2388,6 +2393,7 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
/** /**
* i915_reset_and_wakeup - do process context error handling work * 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 * Fire an error uevent so userspace can see that a hang or error
* was detected. * was detected.
...@@ -2565,7 +2571,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) ...@@ -2565,7 +2571,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
* i915_handle_error - handle a gpu error * i915_handle_error - handle a gpu error
* @dev: drm device * @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 * 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 * sure we get a record and make it available in debugfs. Fire a uevent
* so userspace knows something bad happened (should trigger collection * so userspace knows something bad happened (should trigger collection
...@@ -2778,6 +2784,26 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno) ...@@ -2778,6 +2784,26 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
u64 offset = 0; u64 offset = 0;
int i, backwards; 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)); ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
if (!ipehr_is_semaphore_wait(ring->dev, ipehr)) if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
return NULL; return NULL;
......
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
#define GRDOM_RESET_STATUS (1<<1) #define GRDOM_RESET_STATUS (1<<1)
#define GRDOM_RESET_ENABLE (1<<0) #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_FULL (0<<1)
#define ILK_GRDOM_RENDER (1<<1) #define ILK_GRDOM_RENDER (1<<1)
#define ILK_GRDOM_MEDIA (3<<1) #define ILK_GRDOM_MEDIA (3<<1)
...@@ -536,6 +536,10 @@ ...@@ -536,6 +536,10 @@
#define GEN7_3DPRIM_START_INSTANCE 0x243C #define GEN7_3DPRIM_START_INSTANCE 0x243C
#define GEN7_3DPRIM_BASE_VERTEX 0x2440 #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 OACONTROL 0x2360
#define _GEN7_PIPEA_DE_LOAD_SL 0x70068 #define _GEN7_PIPEA_DE_LOAD_SL 0x70068
...@@ -728,12 +732,13 @@ enum skl_disp_power_wells { ...@@ -728,12 +732,13 @@ enum skl_disp_power_wells {
#define DSI_PLL_N1_DIV_MASK (3 << 16) #define DSI_PLL_N1_DIV_MASK (3 << 16)
#define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_SHIFT 0
#define DSI_PLL_M1_DIV_MASK (0x1ff << 0) #define DSI_PLL_M1_DIV_MASK (0x1ff << 0)
#define CCK_CZ_CLOCK_CONTROL 0x62
#define CCK_DISPLAY_CLOCK_CONTROL 0x6b #define CCK_DISPLAY_CLOCK_CONTROL 0x6b
#define DISPLAY_TRUNK_FORCE_ON (1 << 17) #define CCK_TRUNK_FORCE_ON (1 << 17)
#define DISPLAY_TRUNK_FORCE_OFF (1 << 16) #define CCK_TRUNK_FORCE_OFF (1 << 16)
#define DISPLAY_FREQUENCY_STATUS (0x1f << 8) #define CCK_FREQUENCY_STATUS (0x1f << 8)
#define DISPLAY_FREQUENCY_STATUS_SHIFT 8 #define CCK_FREQUENCY_STATUS_SHIFT 8
#define DISPLAY_FREQUENCY_VALUES (0x1f << 0) #define CCK_FREQUENCY_VALUES (0x1f << 0)
/** /**
* DOC: DPIO * DOC: DPIO
...@@ -1395,7 +1400,8 @@ enum skl_disp_power_wells { ...@@ -1395,7 +1400,8 @@ enum skl_disp_power_wells {
#define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \ #define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \
_PORT_TX_DW3_LN0_B, \ _PORT_TX_DW3_LN0_B, \
_PORT_TX_DW3_LN0_C) _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_A 0x162510
#define _PORT_TX_DW4_LN0_B 0x6C510 #define _PORT_TX_DW4_LN0_B 0x6C510
...@@ -1436,9 +1442,15 @@ enum skl_disp_power_wells { ...@@ -1436,9 +1442,15 @@ enum skl_disp_power_wells {
/* /*
* Fence registers * 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(i) (0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
#define FENCE_REG_945_8 0x3000
#define I830_FENCE_START_MASK 0x07f80000 #define I830_FENCE_START_MASK 0x07f80000
#define I830_FENCE_TILING_Y_SHIFT 12 #define I830_FENCE_TILING_Y_SHIFT 12
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
...@@ -1451,14 +1463,16 @@ enum skl_disp_power_wells { ...@@ -1451,14 +1463,16 @@ enum skl_disp_power_wells {
#define I915_FENCE_START_MASK 0x0ff00000 #define I915_FENCE_START_MASK 0x0ff00000
#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) #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_PITCH_SHIFT 2
#define I965_FENCE_TILING_Y_SHIFT 1 #define I965_FENCE_TILING_Y_SHIFT 1
#define I965_FENCE_REG_VALID (1<<0) #define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400 #define I965_FENCE_MAX_PITCH_VAL 0x0400
#define FENCE_REG_SANDYBRIDGE_0 0x100000 #define FENCE_REG_GEN6_LO(i) (0x100000 + (i) * 8)
#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32 #define FENCE_REG_GEN6_HI(i) (0x100000 + (i) * 8 + 4)
#define GEN6_FENCE_PITCH_SHIFT 32
#define GEN7_FENCE_MAX_PITCH_VAL 0x0800 #define GEN7_FENCE_MAX_PITCH_VAL 0x0800
...@@ -1542,7 +1556,8 @@ enum skl_disp_power_wells { ...@@ -1542,7 +1556,8 @@ enum skl_disp_power_wells {
#define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3) #define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3)
#define RING_FAULT_VALID (1<<0) #define RING_FAULT_VALID (1<<0)
#define DONE_REG 0x40b0 #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 BSD_HWS_PGA_GEN7 (0x04180)
#define BLT_HWS_PGA_GEN7 (0x04280) #define BLT_HWS_PGA_GEN7 (0x04280)
#define VEBOX_HWS_PGA_GEN7 (0x04380) #define VEBOX_HWS_PGA_GEN7 (0x04380)
...@@ -1582,14 +1597,17 @@ enum skl_disp_power_wells { ...@@ -1582,14 +1597,17 @@ enum skl_disp_power_wells {
#endif #endif
#define IPEIR_I965 0x02064 #define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068 #define IPEHR_I965 0x02068
#define INSTDONE_I965 0x0206c
#define GEN7_INSTDONE_1 0x0206c
#define GEN7_SC_INSTDONE 0x07100 #define GEN7_SC_INSTDONE 0x07100
#define GEN7_SAMPLER_INSTDONE 0x0e160 #define GEN7_SAMPLER_INSTDONE 0x0e160
#define GEN7_ROW_INSTDONE 0x0e164 #define GEN7_ROW_INSTDONE 0x0e164
#define I915_NUM_INSTDONE_REG 4 #define I915_NUM_INSTDONE_REG 4
#define RING_IPEIR(base) ((base)+0x64) #define RING_IPEIR(base) ((base)+0x64)
#define RING_IPEHR(base) ((base)+0x68) #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_INSTDONE(base) ((base)+0x6c)
#define RING_INSTPS(base) ((base)+0x70) #define RING_INSTPS(base) ((base)+0x70)
#define RING_DMA_FADD(base) ((base)+0x78) #define RING_DMA_FADD(base) ((base)+0x78)
...@@ -1597,7 +1615,7 @@ enum skl_disp_power_wells { ...@@ -1597,7 +1615,7 @@ enum skl_disp_power_wells {
#define RING_INSTPM(base) ((base)+0xc0) #define RING_INSTPM(base) ((base)+0xc0)
#define RING_MI_MODE(base) ((base)+0x9c) #define RING_MI_MODE(base) ((base)+0x9c)
#define INSTPS 0x02070 /* 965+ only */ #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 ACTHD_I965 0x02074
#define HWS_PGA 0x02080 #define HWS_PGA 0x02080
#define HWS_ADDRESS_MASK 0xfffff000 #define HWS_ADDRESS_MASK 0xfffff000
...@@ -1606,7 +1624,7 @@ enum skl_disp_power_wells { ...@@ -1606,7 +1624,7 @@ enum skl_disp_power_wells {
#define PWRCTX_EN (1<<0) #define PWRCTX_EN (1<<0)
#define IPEIR 0x02088 #define IPEIR 0x02088
#define IPEHR 0x0208c #define IPEHR 0x0208c
#define INSTDONE 0x02090 #define GEN2_INSTDONE 0x02090
#define NOPID 0x02094 #define NOPID 0x02094
#define HWSTAM 0x02098 #define HWSTAM 0x02098
#define DMA_FADD_I8XX 0x020d0 #define DMA_FADD_I8XX 0x020d0
...@@ -1876,12 +1894,27 @@ enum skl_disp_power_wells { ...@@ -1876,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 CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
#define GEN8_FUSE2 0x9120 #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_SHIFT 25
#define GEN8_F2_S_ENA_MASK (0x7 << GEN8_F2_S_ENA_SHIFT) #define GEN8_F2_S_ENA_MASK (0x7 << GEN8_F2_S_ENA_SHIFT)
#define GEN9_F2_SS_DIS_SHIFT 20 #define GEN9_F2_SS_DIS_SHIFT 20
#define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT) #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 GEN9_EU_DISABLE(slice) (0x9134 + (slice)*0x4)
#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 #define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
...@@ -2475,8 +2508,8 @@ enum skl_disp_power_wells { ...@@ -2475,8 +2508,8 @@ enum skl_disp_power_wells {
#define PALETTE_A_OFFSET 0xa000 #define PALETTE_A_OFFSET 0xa000
#define PALETTE_B_OFFSET 0xa800 #define PALETTE_B_OFFSET 0xa800
#define CHV_PALETTE_C_OFFSET 0xc000 #define CHV_PALETTE_C_OFFSET 0xc000
#define PALETTE(pipe) (dev_priv->info.palette_offsets[pipe] + \ #define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \
dev_priv->info.display_mmio_offset) dev_priv->info.display_mmio_offset + (i) * 4)
/* MCH MMIO space */ /* MCH MMIO space */
...@@ -2807,8 +2840,11 @@ enum skl_disp_power_wells { ...@@ -2807,8 +2840,11 @@ enum skl_disp_power_wells {
#define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_28_US(us) (((us) * 100) >> 7)
#define INTERVAL_1_33_US(us) (((us) * 3) >> 2) #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) ? \ #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)) INTERVAL_1_28_US(us))
/* /*
...@@ -3264,7 +3300,9 @@ enum skl_disp_power_wells { ...@@ -3264,7 +3300,9 @@ enum skl_disp_power_wells {
#define GEN3_SDVOC 0x61160 #define GEN3_SDVOC 0x61160
#define GEN4_HDMIB GEN3_SDVOB #define GEN4_HDMIB GEN3_SDVOB
#define GEN4_HDMIC GEN3_SDVOC #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_SDVOB 0xe1140
#define PCH_HDMIB PCH_SDVOB #define PCH_HDMIB PCH_SDVOB
#define PCH_HDMIC 0xe1150 #define PCH_HDMIC 0xe1150
...@@ -3596,17 +3634,29 @@ enum skl_disp_power_wells { ...@@ -3596,17 +3634,29 @@ enum skl_disp_power_wells {
#define UTIL_PIN_CTL 0x48400 #define UTIL_PIN_CTL 0x48400
#define UTIL_PIN_ENABLE (1 << 31) #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. */ /* 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_ENABLE (1 << 31)
#define BXT_BLC_PWM_POLARITY (1 << 29) #define BXT_BLC_PWM_POLARITY (1 << 29)
#define BXT_BLC_PWM_FREQ1 0xC8254 #define _BXT_BLC_PWM_FREQ1 0xC8254
#define BXT_BLC_PWM_DUTY1 0xC8258 #define _BXT_BLC_PWM_DUTY1 0xC8258
#define BXT_BLC_PWM_CTL2 0xC8350 #define _BXT_BLC_PWM_CTL2 0xC8350
#define BXT_BLC_PWM_FREQ2 0xC8354 #define _BXT_BLC_PWM_FREQ2 0xC8354
#define BXT_BLC_PWM_DUTY2 0xC8358 #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_CTL 0xe7000
#define PCH_GTC_ENABLE (1 << 31) #define PCH_GTC_ENABLE (1 << 31)
...@@ -4093,6 +4143,10 @@ enum skl_disp_power_wells { ...@@ -4093,6 +4143,10 @@ enum skl_disp_power_wells {
#define DP_C 0x64200 #define DP_C 0x64200
#define DP_D 0x64300 #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_PORT_EN (1 << 31)
#define DP_PIPEB_SELECT (1 << 30) #define DP_PIPEB_SELECT (1 << 30)
#define DP_PIPE_MASK (1 << 30) #define DP_PIPE_MASK (1 << 30)
...@@ -5631,7 +5685,7 @@ enum skl_disp_power_wells { ...@@ -5631,7 +5685,7 @@ enum skl_disp_power_wells {
/* legacy palette */ /* legacy palette */
#define _LGC_PALETTE_A 0x4a000 #define _LGC_PALETTE_A 0x4a000
#define _LGC_PALETTE_B 0x4a800 #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_A 0x4a480
#define _GAMMA_MODE_B 0x4ac80 #define _GAMMA_MODE_B 0x4ac80
...@@ -6868,6 +6922,9 @@ enum skl_disp_power_wells { ...@@ -6868,6 +6922,9 @@ enum skl_disp_power_wells {
#define GEN6_RC6 3 #define GEN6_RC6 3
#define GEN6_RC7 4 #define GEN6_RC7 4
#define GEN8_GT_SLICE_INFO 0x138064
#define GEN8_LSLICESTAT_MASK 0x7
#define CHV_POWER_SS0_SIG1 0xa720 #define CHV_POWER_SS0_SIG1 0xa720
#define CHV_POWER_SS1_SIG1 0xa728 #define CHV_POWER_SS1_SIG1 0xa728
#define CHV_SS_PG_ENABLE (1<<1) #define CHV_SS_PG_ENABLE (1<<1)
...@@ -7403,8 +7460,8 @@ enum skl_disp_power_wells { ...@@ -7403,8 +7460,8 @@ enum skl_disp_power_wells {
#define DPLL_CFGCR2_PDIV_7 (4<<2) #define DPLL_CFGCR2_PDIV_7 (4<<2)
#define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
#define GET_CFG_CR1_REG(id) (DPLL1_CFGCR1 + (id - SKL_DPLL1) * 8) #define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8)
#define GET_CFG_CR2_REG(id) (DPLL1_CFGCR2 + (id - SKL_DPLL1) * 8) #define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8)
/* BXT display engine PLL */ /* BXT display engine PLL */
#define BXT_DE_PLL_CTL 0x6d000 #define BXT_DE_PLL_CTL 0x6d000
...@@ -7509,6 +7566,68 @@ enum skl_disp_power_wells { ...@@ -7509,6 +7566,68 @@ enum skl_disp_power_wells {
#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */ #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 */ /* BXT MIPI mode configure */
#define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8 #define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8
#define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8 #define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8
...@@ -7550,6 +7669,13 @@ enum skl_disp_power_wells { ...@@ -7550,6 +7669,13 @@ enum skl_disp_power_wells {
#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190)
#define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) #define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) #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 DPI_ENABLE (1 << 31) /* A + C */
#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27
#define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27) #define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27)
......
...@@ -39,7 +39,7 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) ...@@ -39,7 +39,7 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u64 raw_time; /* 32b value may overflow during fixed point math */ 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; u32 ret;
if (!intel_enable_rc6(dev)) if (!intel_enable_rc6(dev))
...@@ -49,41 +49,19 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) ...@@ -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 */ /* On VLV and CHV, residency time is in CZ units rather than 1.28us */
if (IS_VALLEYVIEW(dev)) { if (IS_VALLEYVIEW(dev)) {
u32 clk_reg, czcount_30ns; units = 1;
div = dev_priv->czclk_freq;
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);
}
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
units <<= 8; units <<= 8;
} else if (IS_BROXTON(dev)) {
div = div * bias; units = 1;
div = 1200; /* 833.33ns */
} }
raw_time = I915_READ(reg) * units; raw_time = I915_READ(reg) * units;
ret = DIV_ROUND_UP_ULL(raw_time, div); ret = DIV_ROUND_UP_ULL(raw_time, div);
out:
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
return ret; return ret;
} }
......
...@@ -107,6 +107,26 @@ TRACE_EVENT(i915_gem_object_create, ...@@ -107,6 +107,26 @@ TRACE_EVENT(i915_gem_object_create,
TP_printk("obj=%p, size=%u", __entry->obj, __entry->size) 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, TRACE_EVENT(i915_vma_bind,
TP_PROTO(struct i915_vma *vma, unsigned flags), TP_PROTO(struct i915_vma *vma, unsigned flags),
TP_ARGS(vma, flags), TP_ARGS(vma, flags),
......
...@@ -94,6 +94,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) ...@@ -94,6 +94,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
crtc_state->update_pipe = false; crtc_state->update_pipe = false;
crtc_state->disable_lp_wm = false;
return &crtc_state->base; return &crtc_state->base;
} }
......
...@@ -50,6 +50,11 @@ ...@@ -50,6 +50,11 @@
* co-operation between the graphics and audio drivers is handled via audio * co-operation between the graphics and audio drivers is handled via audio
* related registers. (The notable exception is the power management, not * related registers. (The notable exception is the power management, not
* covered here.) * 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 { static const struct {
...@@ -68,18 +73,44 @@ static const struct { ...@@ -68,18 +73,44 @@ static const struct {
{ 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 }, { 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
}; };
/* HDMI N/CTS table */
#define TMDS_297M 297000
#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
static const struct {
int sample_rate;
int clock;
int n;
int cts;
} aud_ncts[] = {
{ 44100, TMDS_296M, 4459, 234375 },
{ 44100, TMDS_297M, 4704, 247500 },
{ 48000, TMDS_296M, 5824, 281250 },
{ 48000, TMDS_297M, 5120, 247500 },
{ 32000, TMDS_296M, 5824, 421875 },
{ 32000, TMDS_297M, 3072, 222750 },
{ 88200, TMDS_296M, 8918, 234375 },
{ 88200, TMDS_297M, 9408, 247500 },
{ 96000, TMDS_296M, 11648, 281250 },
{ 96000, TMDS_297M, 10240, 247500 },
{ 176400, TMDS_296M, 17836, 234375 },
{ 176400, TMDS_297M, 18816, 247500 },
{ 192000, TMDS_296M, 23296, 281250 },
{ 192000, TMDS_297M, 20480, 247500 },
};
/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */ /* 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; int i;
for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); 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; break;
} }
if (i == ARRAY_SIZE(hdmi_audio_clock)) { 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; i = 1;
} }
...@@ -90,6 +121,45 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode) ...@@ -90,6 +121,45 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
return hdmi_audio_clock[i].config; return hdmi_audio_clock[i].config;
} }
static int audio_config_get_n(const struct drm_display_mode *mode, int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) {
if ((rate == aud_ncts[i].sample_rate) &&
(mode->clock == aud_ncts[i].clock)) {
return aud_ncts[i].n;
}
}
return 0;
}
static uint32_t audio_config_setup_n_reg(int n, uint32_t val)
{
int n_low, n_up;
uint32_t tmp = val;
n_low = n & 0xfff;
n_up = (n >> 12) & 0xff;
tmp &= ~(AUD_CONFIG_UPPER_N_MASK | AUD_CONFIG_LOWER_N_MASK);
tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) |
(n_low << AUD_CONFIG_LOWER_N_SHIFT) |
AUD_CONFIG_N_PROG_ENABLE);
return tmp;
}
/* check whether N/CTS/M need be set manually */
static bool audio_rate_need_prog(struct intel_crtc *crtc,
const struct drm_display_mode *mode)
{
if (((mode->clock == TMDS_297M) ||
(mode->clock == TMDS_296M)) &&
intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI))
return true;
else
return false;
}
static bool intel_eld_uptodate(struct drm_connector *connector, static bool intel_eld_uptodate(struct drm_connector *connector,
int reg_eldv, uint32_t bits_eldv, int reg_eldv, uint32_t bits_eldv,
int reg_elda, uint32_t bits_elda, int reg_elda, uint32_t bits_elda,
...@@ -138,7 +208,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder) ...@@ -138,7 +208,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder)
static void g4x_audio_codec_enable(struct drm_connector *connector, static void g4x_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder, 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 drm_i915_private *dev_priv = connector->dev->dev_private;
uint8_t *eld = connector->eld; uint8_t *eld = connector->eld;
...@@ -184,6 +254,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) ...@@ -184,6 +254,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe)); DRM_DEBUG_KMS("Disable audio codec on pipe %c\n", pipe_name(pipe));
mutex_lock(&dev_priv->av_mutex);
/* Disable timestamps */ /* Disable timestamps */
tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
...@@ -199,22 +271,31 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder) ...@@ -199,22 +271,31 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
tmp &= ~AUDIO_ELD_VALID(pipe); tmp &= ~AUDIO_ELD_VALID(pipe);
tmp &= ~AUDIO_OUTPUT_ENABLE(pipe); tmp &= ~AUDIO_OUTPUT_ENABLE(pipe);
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
mutex_unlock(&dev_priv->av_mutex);
} }
static void hsw_audio_codec_enable(struct drm_connector *connector, static void hsw_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder, 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 drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
enum pipe pipe = intel_crtc->pipe; enum pipe pipe = intel_crtc->pipe;
struct i915_audio_component *acomp = dev_priv->audio_component;
const uint8_t *eld = connector->eld; const uint8_t *eld = connector->eld;
struct intel_digital_port *intel_dig_port =
enc_to_dig_port(&encoder->base);
enum port port = intel_dig_port->port;
uint32_t tmp; uint32_t tmp;
int len, i; int len, i;
int n, rate;
DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n", DRM_DEBUG_KMS("Enable audio codec on pipe %c, %u bytes ELD\n",
pipe_name(pipe), drm_eld_size(eld)); pipe_name(pipe), drm_eld_size(eld));
mutex_lock(&dev_priv->av_mutex);
/* Enable audio presence detect, invalidate ELD */ /* Enable audio presence detect, invalidate ELD */
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
tmp |= AUDIO_OUTPUT_ENABLE(pipe); tmp |= AUDIO_OUTPUT_ENABLE(pipe);
...@@ -246,13 +327,32 @@ static void hsw_audio_codec_enable(struct drm_connector *connector, ...@@ -246,13 +327,32 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
/* Enable timestamps */ /* Enable timestamps */
tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_VALUE_INDEX; tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK; tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
tmp |= AUD_CONFIG_N_VALUE_INDEX; tmp |= AUD_CONFIG_N_VALUE_INDEX;
else 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, adjusted_mode)) {
if (!acomp)
rate = 0;
else if (port >= PORT_A && port <= PORT_E)
rate = acomp->aud_sample_rate[port];
else {
DRM_ERROR("invalid port: %d\n", port);
rate = 0;
}
n = audio_config_get_n(adjusted_mode, rate);
if (n != 0)
tmp = audio_config_setup_n_reg(n, tmp);
else
DRM_DEBUG_KMS("no suitable N value is found\n");
}
I915_WRITE(HSW_AUD_CFG(pipe), tmp); I915_WRITE(HSW_AUD_CFG(pipe), tmp);
mutex_unlock(&dev_priv->av_mutex);
} }
static void ilk_audio_codec_disable(struct intel_encoder *encoder) static void ilk_audio_codec_disable(struct intel_encoder *encoder)
...@@ -304,7 +404,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) ...@@ -304,7 +404,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
static void ilk_audio_codec_enable(struct drm_connector *connector, static void ilk_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder, 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 drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
...@@ -381,7 +481,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, ...@@ -381,7 +481,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT)) if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
tmp |= AUD_CONFIG_N_VALUE_INDEX; tmp |= AUD_CONFIG_N_VALUE_INDEX;
else else
tmp |= audio_config_hdmi_pixel_clock(mode); tmp |= audio_config_hdmi_pixel_clock(adjusted_mode);
I915_WRITE(aud_config, tmp); I915_WRITE(aud_config, tmp);
} }
...@@ -396,7 +496,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) ...@@ -396,7 +496,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
{ {
struct drm_encoder *encoder = &intel_encoder->base; struct drm_encoder *encoder = &intel_encoder->base;
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); 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_connector *connector;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -419,10 +519,11 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) ...@@ -419,10 +519,11 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
connector->eld[5] |= (1 << 2); 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) 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) if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
...@@ -527,12 +628,91 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev) ...@@ -527,12 +628,91 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
return ret; return ret;
} }
static int i915_audio_component_sync_audio_rate(struct device *dev,
int port, int rate)
{
struct drm_i915_private *dev_priv = dev_to_i915(dev);
struct drm_device *drm_dev = dev_priv->dev;
struct intel_encoder *intel_encoder;
struct intel_digital_port *intel_dig_port;
struct intel_crtc *crtc;
struct drm_display_mode *mode;
struct i915_audio_component *acomp = dev_priv->audio_component;
enum pipe pipe = -1;
u32 tmp;
int n;
/* HSW, BDW SKL need this fix */
if (!IS_SKYLAKE(dev_priv) &&
!IS_BROADWELL(dev_priv) &&
!IS_HASWELL(dev_priv))
return 0;
mutex_lock(&dev_priv->av_mutex);
/* 1. get the pipe */
for_each_intel_encoder(drm_dev, intel_encoder) {
if (intel_encoder->type != INTEL_OUTPUT_HDMI)
continue;
intel_dig_port = enc_to_dig_port(&intel_encoder->base);
if (port == intel_dig_port->port) {
crtc = to_intel_crtc(intel_encoder->base.crtc);
if (!crtc) {
DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__);
continue;
}
pipe = crtc->pipe;
break;
}
}
if (pipe == INVALID_PIPE) {
DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
mutex_unlock(&dev_priv->av_mutex);
return -ENODEV;
}
DRM_DEBUG_KMS("pipe %c connects port %c\n",
pipe_name(pipe), port_name(port));
mode = &crtc->config->base.adjusted_mode;
/* port must be valid now, otherwise the pipe will be invalid */
acomp->aud_sample_rate[port] = rate;
/* 2. check whether to set the N/CTS/M manually or not */
if (!audio_rate_need_prog(crtc, mode)) {
tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
mutex_unlock(&dev_priv->av_mutex);
return 0;
}
n = audio_config_get_n(mode, rate);
if (n == 0) {
DRM_DEBUG_KMS("Using automatic mode for N value on port %c\n",
port_name(port));
tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
mutex_unlock(&dev_priv->av_mutex);
return 0;
}
/* 3. set the N/CTS/M */
tmp = I915_READ(HSW_AUD_CFG(pipe));
tmp = audio_config_setup_n_reg(n, tmp);
I915_WRITE(HSW_AUD_CFG(pipe), tmp);
mutex_unlock(&dev_priv->av_mutex);
return 0;
}
static const struct i915_audio_component_ops i915_audio_component_ops = { static const struct i915_audio_component_ops i915_audio_component_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.get_power = i915_audio_component_get_power, .get_power = i915_audio_component_get_power,
.put_power = i915_audio_component_put_power, .put_power = i915_audio_component_put_power,
.codec_wake_override = i915_audio_component_codec_wake_override, .codec_wake_override = i915_audio_component_codec_wake_override,
.get_cdclk_freq = i915_audio_component_get_cdclk_freq, .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
.sync_audio_rate = i915_audio_component_sync_audio_rate,
}; };
static int i915_audio_component_bind(struct device *i915_dev, static int i915_audio_component_bind(struct device *i915_dev,
...@@ -540,6 +720,7 @@ static int i915_audio_component_bind(struct device *i915_dev, ...@@ -540,6 +720,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
{ {
struct i915_audio_component *acomp = data; struct i915_audio_component *acomp = data;
struct drm_i915_private *dev_priv = dev_to_i915(i915_dev); struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
int i;
if (WARN_ON(acomp->ops || acomp->dev)) if (WARN_ON(acomp->ops || acomp->dev))
return -EEXIST; return -EEXIST;
...@@ -547,6 +728,9 @@ static int i915_audio_component_bind(struct device *i915_dev, ...@@ -547,6 +728,9 @@ static int i915_audio_component_bind(struct device *i915_dev,
drm_modeset_lock_all(dev_priv->dev); drm_modeset_lock_all(dev_priv->dev);
acomp->ops = &i915_audio_component_ops; acomp->ops = &i915_audio_component_ops;
acomp->dev = i915_dev; acomp->dev = i915_dev;
BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
acomp->aud_sample_rate[i] = 0;
dev_priv->audio_component = acomp; dev_priv->audio_component = acomp;
drm_modeset_unlock_all(dev_priv->dev); drm_modeset_unlock_all(dev_priv->dev);
......
...@@ -158,7 +158,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) ...@@ -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 drm_i915_private *dev_priv = dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder); struct intel_crt *crt = intel_encoder_to_crt(encoder);
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 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; u32 adpa;
if (INTEL_INFO(dev)->gen >= 5) if (INTEL_INFO(dev)->gen >= 5)
...@@ -890,7 +890,7 @@ void intel_crt_init(struct drm_device *dev) ...@@ -890,7 +890,7 @@ void intel_crt_init(struct drm_device *dev)
u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT | u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
FDI_RX_LINK_REVERSAL_OVERRIDE; 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); intel_crt_reset(connector);
......
...@@ -265,6 +265,15 @@ void intel_csr_load_program(struct drm_device *dev) ...@@ -265,6 +265,15 @@ void intel_csr_load_program(struct drm_device *dev)
return; 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); mutex_lock(&dev_priv->csr_lock);
fw_size = dev_priv->csr.dmc_fw_size; fw_size = dev_priv->csr.dmc_fw_size;
for (i = 0; i < fw_size; i++) for (i = 0; i < fw_size; i++)
......
...@@ -256,9 +256,6 @@ struct bxt_ddi_buf_trans { ...@@ -256,9 +256,6 @@ struct bxt_ddi_buf_trans {
bool default_index; /* true if the entry represents default value */ 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[] = { static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
/* Idx NT mV diff db */ /* Idx NT mV diff db */
{ 52, 0x9A, 0, 128, true }, /* 0: 400 0 */ { 52, 0x9A, 0, 128, true }, /* 0: 400 0 */
...@@ -273,6 +270,20 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { ...@@ -273,6 +270,20 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
{ 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ { 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. /* BSpec has 2 recommended values - entries 0 and 8.
* Using the entry with higher vswing. * Using the entry with higher vswing.
*/ */
...@@ -298,21 +309,26 @@ static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, ...@@ -298,21 +309,26 @@ static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
enum port *port) enum port *port)
{ {
struct drm_encoder *encoder = &intel_encoder->base; 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; *dig_port = enc_to_mst(encoder)->primary;
*port = (*dig_port)->port; *port = (*dig_port)->port;
} else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || break;
type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { case INTEL_OUTPUT_DISPLAYPORT:
case INTEL_OUTPUT_EDP:
case INTEL_OUTPUT_HDMI:
case INTEL_OUTPUT_UNKNOWN:
*dig_port = enc_to_dig_port(encoder); *dig_port = enc_to_dig_port(encoder);
*port = (*dig_port)->port; *port = (*dig_port)->port;
} else if (type == INTEL_OUTPUT_ANALOG) { break;
case INTEL_OUTPUT_ANALOG:
*dig_port = NULL; *dig_port = NULL;
*port = PORT_E; *port = PORT_E;
} else { break;
DRM_ERROR("Invalid DDI encoder type %d\n", type); default:
BUG(); WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type);
break;
} }
} }
...@@ -542,8 +558,10 @@ void intel_prepare_ddi(struct drm_device *dev) ...@@ -542,8 +558,10 @@ void intel_prepare_ddi(struct drm_device *dev)
enum port port; enum port port;
bool supports_hdmi; 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]) if (visited[port])
continue; continue;
...@@ -592,7 +610,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) ...@@ -592,7 +610,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
* *
* WaFDIAutoLinkSetTimingOverrride:hsw * 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_PWRDN_LANE0_VAL(2) |
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
...@@ -600,13 +618,13 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) ...@@ -600,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 | rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
FDI_RX_PLL_ENABLE | FDI_RX_PLL_ENABLE |
FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes); FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
POSTING_READ(_FDI_RXA_CTL); POSTING_READ(FDI_RX_CTL(PIPE_A));
udelay(220); udelay(220);
/* Switch from Rawclk to PCDclk */ /* Switch from Rawclk to PCDclk */
rx_ctl_val |= FDI_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 */ /* Configure Port Clock Select */
I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel); I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
...@@ -635,21 +653,21 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) ...@@ -635,21 +653,21 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
udelay(600); udelay(600);
/* Program PCH FDI Receiver TU */ /* 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 */ /* Enable PCH FDI Receiver with auto-training */
rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO; rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
POSTING_READ(_FDI_RXA_CTL); POSTING_READ(FDI_RX_CTL(PIPE_A));
/* Wait for FDI receiver lane calibration */ /* Wait for FDI receiver lane calibration */
udelay(30); udelay(30);
/* Unset FDI_RX_MISC pwrdn lanes */ /* 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); temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
I915_WRITE(_FDI_RXA_MISC, temp); I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
POSTING_READ(_FDI_RXA_MISC); POSTING_READ(FDI_RX_MISC(PIPE_A));
/* Wait for FDI auto training time */ /* Wait for FDI auto training time */
udelay(5); udelay(5);
...@@ -683,15 +701,15 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) ...@@ -683,15 +701,15 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
intel_wait_ddi_buf_idle(dev_priv, PORT_E); intel_wait_ddi_buf_idle(dev_priv, PORT_E);
rx_ctl_val &= ~FDI_RX_ENABLE; rx_ctl_val &= ~FDI_RX_ENABLE;
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val); I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
POSTING_READ(_FDI_RXA_CTL); POSTING_READ(FDI_RX_CTL(PIPE_A));
/* Reset FDI_RX_MISC pwrdn lanes */ /* 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_MASK | FDI_RX_PWRDN_LANE0_MASK);
temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
I915_WRITE(_FDI_RXA_MISC, temp); I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
POSTING_READ(_FDI_RXA_MISC); POSTING_READ(FDI_RX_MISC(PIPE_A));
} }
DRM_ERROR("FDI link training failed!\n"); DRM_ERROR("FDI link training failed!\n");
...@@ -953,8 +971,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, ...@@ -953,8 +971,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
uint32_t cfgcr1_val, cfgcr2_val; uint32_t cfgcr1_val, cfgcr2_val;
uint32_t p0, p1, p2, dco_freq; uint32_t p0, p1, p2, dco_freq;
cfgcr1_reg = GET_CFG_CR1_REG(dpll); cfgcr1_reg = DPLL_CFGCR1(dpll);
cfgcr2_reg = GET_CFG_CR2_REG(dpll); cfgcr2_reg = DPLL_CFGCR2(dpll);
cfgcr1_val = I915_READ(cfgcr1_reg); cfgcr1_val = I915_READ(cfgcr1_reg);
cfgcr2_val = I915_READ(cfgcr2_reg); cfgcr2_val = I915_READ(cfgcr2_reg);
...@@ -2027,7 +2045,8 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, ...@@ -2027,7 +2045,8 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc) void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
{ {
struct drm_crtc *crtc = &intel_crtc->base; 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); struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder); enum port port = intel_ddi_get_encoder_port(intel_encoder);
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
...@@ -2112,7 +2131,11 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, ...@@ -2112,7 +2131,11 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
u32 n_entries, i; u32 n_entries, i;
uint32_t val; 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); n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
ddi_translations = bxt_ddi_translations_dp; ddi_translations = bxt_ddi_translations_dp;
} else if (type == INTEL_OUTPUT_HDMI) { } else if (type == INTEL_OUTPUT_HDMI) {
...@@ -2150,9 +2173,13 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, ...@@ -2150,9 +2173,13 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val); I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val);
val = I915_READ(BXT_PORT_TX_DW3_LN0(port)); val = I915_READ(BXT_PORT_TX_DW3_LN0(port));
val &= ~UNIQE_TRANGE_EN_METHOD; val &= ~SCALE_DCOMP_METHOD;
if (ddi_translations[level].enable) 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); I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val);
val = I915_READ(BXT_PORT_TX_DW4_LN0(port)); val = I915_READ(BXT_PORT_TX_DW4_LN0(port));
...@@ -2293,7 +2320,6 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) ...@@ -2293,7 +2320,6 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
if (port != PORT_A || INTEL_INFO(dev)->gen >= 9) if (port != PORT_A || INTEL_INFO(dev)->gen >= 9)
intel_dp_stop_link_train(intel_dp); intel_dp_stop_link_train(intel_dp);
} else if (type == INTEL_OUTPUT_HDMI) { } else if (type == INTEL_OUTPUT_HDMI) {
...@@ -2480,20 +2506,20 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = { ...@@ -2480,20 +2506,20 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = {
{ {
/* DPLL 1 */ /* DPLL 1 */
.ctl = LCPLL2_CTL, .ctl = LCPLL2_CTL,
.cfgcr1 = DPLL1_CFGCR1, .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
.cfgcr2 = DPLL1_CFGCR2, .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
}, },
{ {
/* DPLL 2 */ /* DPLL 2 */
.ctl = WRPLL_CTL1, .ctl = WRPLL_CTL1,
.cfgcr1 = DPLL2_CFGCR1, .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
.cfgcr2 = DPLL2_CFGCR2, .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
}, },
{ {
/* DPLL 3 */ /* DPLL 3 */
.ctl = WRPLL_CTL2, .ctl = WRPLL_CTL2,
.cfgcr1 = DPLL3_CFGCR1, .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
.cfgcr2 = DPLL3_CFGCR2, .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
}, },
}; };
...@@ -2999,22 +3025,22 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc) ...@@ -2999,22 +3025,22 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
intel_ddi_post_disable(intel_encoder); intel_ddi_post_disable(intel_encoder);
val = I915_READ(_FDI_RXA_CTL); val = I915_READ(FDI_RX_CTL(PIPE_A));
val &= ~FDI_RX_ENABLE; 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_MASK | FDI_RX_PWRDN_LANE0_MASK);
val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2); 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; 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; 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, void intel_ddi_get_config(struct intel_encoder *encoder,
......
...@@ -1587,7 +1587,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder) ...@@ -1587,7 +1587,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
enum port port = dp_to_dig_port(intel_dp)->port; enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 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); intel_dp_set_link_params(intel_dp, crtc->config);
...@@ -2604,7 +2604,6 @@ static void intel_enable_dp(struct intel_encoder *encoder) ...@@ -2604,7 +2604,6 @@ static void intel_enable_dp(struct intel_encoder *encoder)
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp); intel_dp_stop_link_train(intel_dp);
if (crtc->config->has_audio) { if (crtc->config->has_audio) {
...@@ -3417,11 +3416,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) ...@@ -3417,11 +3416,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); 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); mutex_unlock(&dev_priv->sb_lock);
return 0; return 0;
...@@ -3696,8 +3690,8 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) ...@@ -3696,8 +3690,8 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
} }
/* Enable corresponding port and start training pattern 1 */ /* Enable corresponding port and start training pattern 1 */
void static void
intel_dp_start_link_train(struct intel_dp *intel_dp) 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_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
struct drm_device *dev = encoder->dev; struct drm_device *dev = encoder->dev;
...@@ -3810,8 +3804,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) ...@@ -3810,8 +3804,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
intel_dp->DP = DP; intel_dp->DP = DP;
} }
void static void
intel_dp_complete_link_train(struct intel_dp *intel_dp) intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
{ {
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev; struct drm_device *dev = dig_port->base.base.dev;
...@@ -3864,7 +3858,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -3864,7 +3858,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
if (!drm_dp_clock_recovery_ok(link_status, if (!drm_dp_clock_recovery_ok(link_status,
intel_dp->lane_count)) { intel_dp->lane_count)) {
intel_dp->train_set_valid = false; 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, intel_dp_set_link_train(intel_dp, &DP,
training_pattern | training_pattern |
DP_LINK_SCRAMBLING_DISABLE); DP_LINK_SCRAMBLING_DISABLE);
...@@ -3881,7 +3875,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -3881,7 +3875,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
/* Try 5 times, then try clock recovery if that fails */ /* Try 5 times, then try clock recovery if that fails */
if (tries > 5) { if (tries > 5) {
intel_dp->train_set_valid = false; 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, intel_dp_set_link_train(intel_dp, &DP,
training_pattern | training_pattern |
DP_LINK_SCRAMBLING_DISABLE); DP_LINK_SCRAMBLING_DISABLE);
...@@ -3914,6 +3908,13 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp) ...@@ -3914,6 +3908,13 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
DP_TRAINING_PATTERN_DISABLE); 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 static void
intel_dp_link_down(struct intel_dp *intel_dp) intel_dp_link_down(struct intel_dp *intel_dp)
{ {
...@@ -4382,7 +4383,6 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp) ...@@ -4382,7 +4383,6 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
!drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) { !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
DRM_DEBUG_KMS("channel EQ not ok, retraining\n"); DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp); intel_dp_stop_link_train(intel_dp);
} }
...@@ -4473,7 +4473,6 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) ...@@ -4473,7 +4473,6 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
intel_encoder->base.name); intel_encoder->base.name);
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp); intel_dp_stop_link_train(intel_dp);
} }
} }
...@@ -6000,7 +5999,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, ...@@ -6000,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_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); intel_panel_setup_backlight(connector, pipe);
return true; return true;
...@@ -6169,10 +6168,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) ...@@ -6169,10 +6168,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
return; return;
intel_connector = intel_connector_alloc(); intel_connector = intel_connector_alloc();
if (!intel_connector) { if (!intel_connector)
kfree(intel_dig_port); goto err_connector_alloc;
return;
}
intel_encoder = &intel_dig_port->base; intel_encoder = &intel_dig_port->base;
encoder = &intel_encoder->base; encoder = &intel_encoder->base;
...@@ -6220,11 +6217,18 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) ...@@ -6220,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; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
dev_priv->hotplug.irq_port[port] = intel_dig_port; dev_priv->hotplug.irq_port[port] = intel_dig_port;
if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { if (!intel_dp_init_connector(intel_dig_port, intel_connector))
goto err_init_connector;
return;
err_init_connector:
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
kfree(intel_connector); kfree(intel_connector);
} err_connector_alloc:
kfree(intel_dig_port);
return;
} }
void intel_dp_mst_suspend(struct drm_device *dev) void intel_dp_mst_suspend(struct drm_device *dev)
......
...@@ -40,7 +40,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -40,7 +40,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct drm_atomic_state *state; struct drm_atomic_state *state;
int bpp, i; int bpp, i;
int lane_count, slots; int lane_count, slots;
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct drm_connector *drm_connector; struct drm_connector *drm_connector;
struct intel_connector *connector, *found = NULL; struct intel_connector *connector, *found = NULL;
struct drm_connector_state *connector_state; struct drm_connector_state *connector_state;
...@@ -78,7 +78,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, ...@@ -78,7 +78,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
return false; 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; pipe_config->pbn = mst_pbn;
slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn); slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
...@@ -188,7 +188,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) ...@@ -188,7 +188,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp); intel_dp_stop_link_train(intel_dp);
} }
......
...@@ -179,12 +179,22 @@ struct intel_panel { ...@@ -179,12 +179,22 @@ struct intel_panel {
bool active_low_pwm; bool active_low_pwm;
/* PWM chip */ /* PWM chip */
bool util_pin_active_low; /* bxt+ */
u8 controller; /* bxt+ only */
struct pwm_device *pwm; struct pwm_device *pwm;
struct backlight_device *device; 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 { struct intel_connector {
...@@ -458,6 +468,9 @@ struct intel_crtc_state { ...@@ -458,6 +468,9 @@ struct intel_crtc_state {
/* w/a for waiting 2 vblanks during crtc enable */ /* w/a for waiting 2 vblanks during crtc enable */
enum pipe hsw_workaround_pipe; enum pipe hsw_workaround_pipe;
/* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */
bool disable_lp_wm;
}; };
struct vlv_wm_state { struct vlv_wm_state {
...@@ -683,7 +696,7 @@ struct intel_hdmi { ...@@ -683,7 +696,7 @@ struct intel_hdmi {
const void *frame, ssize_t len); const void *frame, ssize_t len);
void (*set_infoframes)(struct drm_encoder *encoder, void (*set_infoframes)(struct drm_encoder *encoder,
bool enable, bool enable,
struct drm_display_mode *adjusted_mode); const struct drm_display_mode *adjusted_mode);
bool (*infoframe_enabled)(struct drm_encoder *encoder); bool (*infoframe_enabled)(struct drm_encoder *encoder);
}; };
...@@ -1191,7 +1204,6 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, ...@@ -1191,7 +1204,6 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
void intel_dp_set_link_params(struct intel_dp *intel_dp, void intel_dp_set_link_params(struct intel_dp *intel_dp,
const struct intel_crtc_state *pipe_config); const struct intel_crtc_state *pipe_config);
void intel_dp_start_link_train(struct intel_dp *intel_dp); 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_stop_link_train(struct intel_dp *intel_dp);
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
void intel_dp_encoder_destroy(struct drm_encoder *encoder); void intel_dp_encoder_destroy(struct drm_encoder *encoder);
...@@ -1300,6 +1312,7 @@ int intel_connector_update_modes(struct drm_connector *connector, ...@@ -1300,6 +1312,7 @@ int intel_connector_update_modes(struct drm_connector *connector,
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); 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_force_audio_property(struct drm_connector *connector);
void intel_attach_broadcast_rgb_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 */ /* intel_overlay.c */
...@@ -1332,7 +1345,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) ...@@ -1332,7 +1345,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_enable_backlight(struct intel_connector *connector);
void intel_panel_disable_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_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); enum drm_connector_status intel_panel_detect(struct drm_device *dev);
extern struct drm_display_mode *intel_find_panel_downclock( extern struct drm_display_mode *intel_find_panel_downclock(
struct drm_device *dev, struct drm_device *dev,
...@@ -1387,12 +1399,6 @@ void intel_init_clock_gating(struct drm_device *dev); ...@@ -1387,12 +1399,6 @@ void intel_init_clock_gating(struct drm_device *dev);
void intel_suspend_hw(struct drm_device *dev); void intel_suspend_hw(struct drm_device *dev);
int ilk_wm_max_level(const struct drm_device *dev); int ilk_wm_max_level(const struct drm_device *dev);
void intel_update_watermarks(struct drm_crtc *crtc); void intel_update_watermarks(struct drm_crtc *crtc);
void intel_update_sprite_watermarks(struct drm_plane *plane,
struct drm_crtc *crtc,
uint32_t sprite_width,
uint32_t sprite_height,
int pixel_size,
bool enabled, bool scaled);
void intel_init_pm(struct drm_device *dev); void intel_init_pm(struct drm_device *dev);
void intel_pm_setup(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev);
void intel_gpu_ips_init(struct drm_i915_private *dev_priv); void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
......
...@@ -282,58 +282,46 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder, ...@@ -282,58 +282,46 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
return true; 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 = encoder->base.dev->dev_private;
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); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port; enum port port;
u32 temp; u32 val;
if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { DRM_DEBUG_KMS("\n");
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);
}
/* Exit Low power state in 4 steps*/
for_each_dsi_port(port, intel_dsi->ports) { 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))) { /* 1. Enable MIPI PHY transparent latch */
temp |= (intel_dsi->dual_link - 1) val = I915_READ(BXT_MIPI_PORT_CTRL(port));
<< DUAL_LINK_MODE_SHIFT; I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD);
temp |= intel_crtc->pipe ? usleep_range(2000, 2500);
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));
}
}
static void intel_dsi_port_disable(struct intel_encoder *encoder) /* 2. Enter ULPS */
{ val = I915_READ(MIPI_DEVICE_READY(port));
struct drm_device *dev = encoder->base.dev; val &= ~ULPS_STATE_MASK;
struct drm_i915_private *dev_priv = dev->dev_private; val |= (ULPS_STATE_ENTER | DEVICE_READY);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); I915_WRITE(MIPI_DEVICE_READY(port), val);
enum port port; usleep_range(2, 3);
u32 temp;
/* 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) { /* Clear ULPS and set device ready */
/* de-assert ip_tg_enable signal */ val = I915_READ(MIPI_DEVICE_READY(port));
temp = I915_READ(MIPI_PORT_CTRL(port)); val &= ~ULPS_STATE_MASK;
I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE); val |= DEVICE_READY;
POSTING_READ(MIPI_PORT_CTRL(port)); 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 drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 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) ...@@ -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) static void intel_dsi_enable(struct intel_encoder *encoder)
{ {
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
...@@ -419,19 +476,24 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) ...@@ -419,19 +476,24 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
msleep(intel_dsi->panel_on_delay); msleep(intel_dsi->panel_on_delay);
/* Disable DPOunit clock gating, can stall pipe if (IS_VALLEYVIEW(dev)) {
* and we need DPLL REFA always enabled */ /*
* Disable DPOunit clock gating, can stall pipe
* and we need DPLL REFA always enabled
*/
tmp = I915_READ(DPLL(pipe)); tmp = I915_READ(DPLL(pipe));
tmp |= DPLL_REF_CLK_ENABLE_VLV; tmp |= DPLL_REF_CLK_ENABLE_VLV;
I915_WRITE(DPLL(pipe), tmp); I915_WRITE(DPLL(pipe), tmp);
/* update the hw state for DPLL */ /* update the hw state for DPLL */
intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV | intel_crtc->config->dpll_hw_state.dpll =
DPLL_INTEGRATED_REF_CLK_VLV |
DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
tmp = I915_READ(DSPCLK_GATE_D); tmp = I915_READ(DSPCLK_GATE_D);
tmp |= DPOUNIT_CLOCK_GATE_DISABLE; tmp |= DPOUNIT_CLOCK_GATE_DISABLE;
I915_WRITE(DSPCLK_GATE_D, tmp); I915_WRITE(DSPCLK_GATE_D, tmp);
}
/* put device in ready state */ /* put device in ready state */
intel_dsi_device_ready(encoder); intel_dsi_device_ready(encoder);
...@@ -495,12 +557,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder) ...@@ -495,12 +557,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
/* Panel commands can be sent when clock is in LP11 */ /* Panel commands can be sent when clock is in LP11 */
I915_WRITE(MIPI_DEVICE_READY(port), 0x0); I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
temp = I915_READ(MIPI_CTRL(port)); intel_dsi_reset_clocks(encoder, port);
temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
I915_WRITE(MIPI_CTRL(port), temp |
intel_dsi->escape_clk_div <<
ESCAPE_CLOCK_DIVIDER_SHIFT);
I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
...@@ -519,10 +576,12 @@ static void intel_dsi_disable(struct intel_encoder *encoder) ...@@ -519,10 +576,12 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
static void intel_dsi_clear_device_ready(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 drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port; enum port port;
u32 val; u32 val;
u32 port_ctrl = 0;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
for_each_dsi_port(port, intel_dsi->ports) { for_each_dsi_port(port, intel_dsi->ports) {
...@@ -539,18 +598,22 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) ...@@ -539,18 +598,22 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
ULPS_STATE_ENTER); ULPS_STATE_ENTER);
usleep_range(2000, 2500); 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 /* Wait till Clock lanes are in LP-00 state for MIPI Port A
* only. MIPI Port C has no similar bit for checking * only. MIPI Port C has no similar bit for checking
*/ */
if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT) if (wait_for(((I915_READ(port_ctrl) & AFE_LATCHOUT)
== 0x00000), 30)) == 0x00000), 30))
DRM_ERROR("DSI LP not going Low\n"); DRM_ERROR("DSI LP not going Low\n");
/* Disable MIPI PHY transparent latch /* Disable MIPI PHY transparent latch */
* Common bit for both MIPI Port A & MIPI Port C val = I915_READ(port_ctrl);
*/ I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD);
val = I915_READ(MIPI_PORT_CTRL(PORT_A));
I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD);
usleep_range(1000, 1500); usleep_range(1000, 1500);
I915_WRITE(MIPI_DEVICE_READY(port), 0x00); I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
...@@ -593,7 +656,7 @@ static bool intel_dsi_get_hw_state(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 intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain; enum intel_display_power_domain power_domain;
u32 dpi_enabled, func; u32 dpi_enabled, func, ctrl_reg;
enum port port; enum port port;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
...@@ -605,8 +668,9 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, ...@@ -605,8 +668,9 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
/* XXX: this only works for one DSI output */ /* XXX: this only works for one DSI output */
for_each_dsi_port(port, intel_dsi->ports) { for_each_dsi_port(port, intel_dsi->ports) {
func = I915_READ(MIPI_DSI_FUNC_PRG(port)); func = I915_READ(MIPI_DSI_FUNC_PRG(port));
dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) & ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
DPI_ENABLE; MIPI_PORT_CTRL(port);
dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
/* Due to some hardware limitations on BYT, MIPI Port C DPI /* Due to some hardware limitations on BYT, MIPI Port C DPI
* Enable bit does not get set. To check whether DSI Port C * 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, ...@@ -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, static void intel_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config) struct intel_crtc_state *pipe_config)
{ {
u32 pclk; u32 pclk = 0;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
/* /*
...@@ -640,7 +704,11 @@ static void intel_dsi_get_config(struct intel_encoder *encoder, ...@@ -640,7 +704,11 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
*/ */
pipe_config->dpll_hw_state.dpll_md = 0; pipe_config->dpll_hw_state.dpll_md = 0;
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); pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
if (!pclk) if (!pclk)
return; return;
...@@ -698,7 +766,7 @@ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count, ...@@ -698,7 +766,7 @@ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
} }
static void set_dsi_timings(struct drm_encoder *encoder, 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_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
...@@ -710,10 +778,10 @@ static void set_dsi_timings(struct drm_encoder *encoder, ...@@ -710,10 +778,10 @@ static void set_dsi_timings(struct drm_encoder *encoder,
u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp; u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
hactive = mode->hdisplay; hactive = adjusted_mode->crtc_hdisplay;
hfp = mode->hsync_start - mode->hdisplay; hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay;
hsync = mode->hsync_end - mode->hsync_start; hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
hbp = mode->htotal - mode->hsync_end; hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end;
if (intel_dsi->dual_link) { if (intel_dsi->dual_link) {
hactive /= 2; hactive /= 2;
...@@ -724,9 +792,9 @@ static void set_dsi_timings(struct drm_encoder *encoder, ...@@ -724,9 +792,9 @@ static void set_dsi_timings(struct drm_encoder *encoder,
hbp /= 2; hbp /= 2;
} }
vfp = mode->vsync_start - mode->vdisplay; vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay;
vsync = mode->vsync_end - mode->vsync_start; vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
vbp = mode->vtotal - mode->vsync_end; vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end;
/* horizontal values are in terms of high speed byte clock */ /* horizontal values are in terms of high speed byte clock */
hactive = txbyteclkhs(hactive, bpp, lane_count, hactive = txbyteclkhs(hactive, bpp, lane_count,
...@@ -745,11 +813,11 @@ static void set_dsi_timings(struct drm_encoder *encoder, ...@@ -745,11 +813,11 @@ static void set_dsi_timings(struct drm_encoder *encoder,
* whereas these values should be based on resolution. * whereas these values should be based on resolution.
*/ */
I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port), I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port),
mode->hdisplay); adjusted_mode->crtc_hdisplay);
I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port), I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port),
mode->vdisplay); adjusted_mode->crtc_vdisplay);
I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port), I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port),
mode->vtotal); adjusted_mode->crtc_vtotal);
} }
I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive); I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
...@@ -774,8 +842,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) ...@@ -774,8 +842,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
struct drm_display_mode *adjusted_mode = const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
&intel_crtc->config->base.adjusted_mode;
enum port port; enum port port;
unsigned int bpp = intel_crtc->config->pipe_bpp; unsigned int bpp = intel_crtc->config->pipe_bpp;
u32 val, tmp; u32 val, tmp;
...@@ -783,7 +850,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) ...@@ -783,7 +850,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe)); 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) { if (intel_dsi->dual_link) {
mode_hdisplay /= 2; mode_hdisplay /= 2;
...@@ -833,7 +900,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) ...@@ -833,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_DPHY_PARAM(port), intel_dsi->dphy_reg);
I915_WRITE(MIPI_DPI_RESOLUTION(port), I915_WRITE(MIPI_DPI_RESOLUTION(port),
adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT |
mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT); mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
} }
...@@ -879,13 +946,13 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder) ...@@ -879,13 +946,13 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
if (is_vid_mode(intel_dsi) && if (is_vid_mode(intel_dsi) &&
intel_dsi->video_mode_format == VIDEO_MODE_BURST) { intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
I915_WRITE(MIPI_HS_TX_TIMEOUT(port), I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
txbyteclkhs(adjusted_mode->htotal, bpp, txbyteclkhs(adjusted_mode->crtc_htotal, bpp,
intel_dsi->lane_count, intel_dsi->lane_count,
intel_dsi->burst_mode_ratio) + 1); intel_dsi->burst_mode_ratio) + 1);
} else { } else {
I915_WRITE(MIPI_HS_TX_TIMEOUT(port), I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
txbyteclkhs(adjusted_mode->vtotal * txbyteclkhs(adjusted_mode->crtc_vtotal *
adjusted_mode->htotal, adjusted_mode->crtc_htotal,
bpp, intel_dsi->lane_count, bpp, intel_dsi->lane_count,
intel_dsi->burst_mode_ratio) + 1); intel_dsi->burst_mode_ratio) + 1);
} }
......
...@@ -127,6 +127,9 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) ...@@ -127,6 +127,9 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
extern void intel_enable_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 void intel_disable_dsi_pll(struct intel_encoder *encoder);
extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp); 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); struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id);
......
...@@ -384,6 +384,90 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp) ...@@ -384,6 +384,90 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp)
return pclk; 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) static bool bxt_configure_dsi_pll(struct intel_encoder *encoder)
{ {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
...@@ -435,6 +519,8 @@ static bool bxt_configure_dsi_pll(struct intel_encoder *encoder) ...@@ -435,6 +519,8 @@ static bool bxt_configure_dsi_pll(struct intel_encoder *encoder)
static void bxt_enable_dsi_pll(struct intel_encoder *encoder) static void bxt_enable_dsi_pll(struct intel_encoder *encoder)
{ {
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; 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 val;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
...@@ -453,6 +539,10 @@ static void bxt_enable_dsi_pll(struct intel_encoder *encoder) ...@@ -453,6 +539,10 @@ static void bxt_enable_dsi_pll(struct intel_encoder *encoder)
return; 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 */ /* Enable DSI PLL */
val = I915_READ(BXT_DSI_PLL_ENABLE); val = I915_READ(BXT_DSI_PLL_ENABLE);
val |= BXT_DSI_PLL_DO_ENABLE; val |= BXT_DSI_PLL_DO_ENABLE;
...@@ -486,3 +576,29 @@ void intel_disable_dsi_pll(struct intel_encoder *encoder) ...@@ -486,3 +576,29 @@ void intel_disable_dsi_pll(struct intel_encoder *encoder)
else if (IS_BROXTON(dev)) else if (IS_BROXTON(dev))
bxt_disable_dsi_pll(encoder); 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);
}
...@@ -97,7 +97,8 @@ struct intel_dvo { ...@@ -97,7 +97,8 @@ struct intel_dvo {
struct intel_dvo_device dev; struct intel_dvo_device dev;
struct drm_display_mode *panel_fixed_mode; struct intel_connector *attached_connector;
bool panel_wants_dither; bool panel_wants_dither;
}; };
...@@ -201,6 +202,8 @@ intel_dvo_mode_valid(struct drm_connector *connector, ...@@ -201,6 +202,8 @@ intel_dvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct intel_dvo *intel_dvo = intel_attached_dvo(connector); 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 max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
int target_clock = mode->clock; int target_clock = mode->clock;
...@@ -209,13 +212,13 @@ intel_dvo_mode_valid(struct drm_connector *connector, ...@@ -209,13 +212,13 @@ intel_dvo_mode_valid(struct drm_connector *connector,
/* XXX: Validate clock range */ /* XXX: Validate clock range */
if (intel_dvo->panel_fixed_mode) { if (fixed_mode) {
if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay) if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL; return MODE_PANEL;
if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay) if (mode->vdisplay > fixed_mode->vdisplay)
return MODE_PANEL; return MODE_PANEL;
target_clock = intel_dvo->panel_fixed_mode->clock; target_clock = fixed_mode->clock;
} }
if (target_clock > max_dotclk) if (target_clock > max_dotclk)
...@@ -228,6 +231,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, ...@@ -228,6 +231,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config) struct intel_crtc_state *pipe_config)
{ {
struct intel_dvo *intel_dvo = enc_to_dvo(encoder); 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; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* If we have timings from the BIOS for the panel, put them in /* If we have timings from the BIOS for the panel, put them in
...@@ -235,21 +240,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder, ...@@ -235,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 * with the panel scaling set up to source from the H/VDisplay
* of the original mode. * of the original mode.
*/ */
if (intel_dvo->panel_fixed_mode != NULL) { if (fixed_mode)
#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x intel_fixed_panel_mode(fixed_mode, adjusted_mode);
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);
}
return true; return true;
} }
...@@ -259,7 +251,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder) ...@@ -259,7 +251,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 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); struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
int pipe = crtc->pipe; int pipe = crtc->pipe;
u32 dvo_val; u32 dvo_val;
...@@ -293,11 +285,11 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder) ...@@ -293,11 +285,11 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
dvo_val |= DVO_VSYNC_ACTIVE_HIGH; dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
/*I915_WRITE(DVOB_SRCDIM, /*I915_WRITE(DVOB_SRCDIM,
(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
(adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
I915_WRITE(dvo_srcdim_reg, I915_WRITE(dvo_srcdim_reg,
(adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
(adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
/*I915_WRITE(DVOB, dvo_val);*/ /*I915_WRITE(DVOB, dvo_val);*/
I915_WRITE(dvo_reg, dvo_val); I915_WRITE(dvo_reg, dvo_val);
} }
...@@ -318,8 +310,9 @@ intel_dvo_detect(struct drm_connector *connector, bool force) ...@@ -318,8 +310,9 @@ intel_dvo_detect(struct drm_connector *connector, bool force)
static int intel_dvo_get_modes(struct drm_connector *connector) 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; 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 /* 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 * devices which will have a fixed set of modes determined by the chip
...@@ -331,9 +324,9 @@ static int intel_dvo_get_modes(struct drm_connector *connector) ...@@ -331,9 +324,9 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
if (!list_empty(&connector->probed_modes)) if (!list_empty(&connector->probed_modes))
return 1; return 1;
if (intel_dvo->panel_fixed_mode != NULL) { if (fixed_mode) {
struct drm_display_mode *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) { if (mode) {
drm_mode_probed_add(connector, mode); drm_mode_probed_add(connector, mode);
return 1; return 1;
...@@ -346,6 +339,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector) ...@@ -346,6 +339,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
static void intel_dvo_destroy(struct drm_connector *connector) static void intel_dvo_destroy(struct drm_connector *connector)
{ {
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
intel_panel_fini(&to_intel_connector(connector)->panel);
kfree(connector); kfree(connector);
} }
...@@ -372,8 +366,6 @@ static void intel_dvo_enc_destroy(struct drm_encoder *encoder) ...@@ -372,8 +366,6 @@ static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
if (intel_dvo->dev.dev_ops->destroy) if (intel_dvo->dev.dev_ops->destroy)
intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev); intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
kfree(intel_dvo->panel_fixed_mode);
intel_encoder_destroy(encoder); intel_encoder_destroy(encoder);
} }
...@@ -438,6 +430,8 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -438,6 +430,8 @@ void intel_dvo_init(struct drm_device *dev)
return; return;
} }
intel_dvo->attached_connector = intel_connector;
intel_encoder = &intel_dvo->base; intel_encoder = &intel_dvo->base;
drm_encoder_init(dev, &intel_encoder->base, drm_encoder_init(dev, &intel_encoder->base,
&intel_dvo_enc_funcs, encoder_type); &intel_dvo_enc_funcs, encoder_type);
...@@ -542,8 +536,9 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -542,8 +536,9 @@ void intel_dvo_init(struct drm_device *dev)
* headers, likely), so for now, just get the current * headers, likely), so for now, just get the current
* mode being output through DVO. * mode being output through DVO.
*/ */
intel_dvo->panel_fixed_mode = intel_panel_init(&intel_connector->panel,
intel_dvo_get_current_mode(connector); intel_dvo_get_current_mode(connector),
NULL);
intel_dvo->panel_wants_dither = true; intel_dvo->panel_wants_dither = true;
} }
......
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_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 * 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 * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's
...@@ -439,7 +444,7 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) ...@@ -439,7 +444,7 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
*/ */
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; return;
mutex_lock(&dev_priv->fbc.lock); mutex_lock(&dev_priv->fbc.lock);
...@@ -457,7 +462,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) ...@@ -457,7 +462,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc)
{ {
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
if (!dev_priv->fbc.enable_fbc) if (!fbc_supported(dev_priv))
return; return;
mutex_lock(&dev_priv->fbc.lock); mutex_lock(&dev_priv->fbc.lock);
...@@ -685,7 +690,7 @@ static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) ...@@ -685,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) void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
{ {
if (!dev_priv->fbc.enable_fbc) if (!fbc_supported(dev_priv))
return; return;
mutex_lock(&dev_priv->fbc.lock); mutex_lock(&dev_priv->fbc.lock);
...@@ -693,16 +698,61 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) ...@@ -693,16 +698,61 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
mutex_unlock(&dev_priv->fbc.lock); 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) if (size <= dev_priv->fbc.uncompressed_size)
return 0; return 0;
/* Release any current block */ /* Release any current block */
__intel_fbc_cleanup_cfb(dev_priv); __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, static bool stride_is_valid(struct drm_i915_private *dev_priv,
...@@ -749,6 +799,35 @@ static bool pixel_format_is_valid(struct drm_framebuffer *fb) ...@@ -749,6 +799,35 @@ static bool pixel_format_is_valid(struct drm_framebuffer *fb)
} }
} }
/*
* 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;
}
/** /**
* __intel_fbc_update - enable/disable FBC as needed, unlocked * __intel_fbc_update - enable/disable FBC as needed, unlocked
* @dev_priv: i915 device instance * @dev_priv: i915 device instance
...@@ -775,7 +854,6 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) ...@@ -775,7 +854,6 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode; const struct drm_display_mode *adjusted_mode;
unsigned int max_width, max_height;
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
...@@ -824,21 +902,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) ...@@ -824,21 +902,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
goto out_disable; goto out_disable;
} }
if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) {
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) {
set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE);
goto out_disable; goto out_disable;
} }
if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) && if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) &&
intel_crtc->plane != PLANE_A) { intel_crtc->plane != PLANE_A) {
set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); set_no_fbc_reason(dev_priv, FBC_BAD_PLANE);
...@@ -883,8 +951,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) ...@@ -883,8 +951,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
goto out_disable; goto out_disable;
} }
if (intel_fbc_setup_cfb(dev_priv, obj->base.size, if (intel_fbc_setup_cfb(intel_crtc)) {
drm_format_plane_cpp(fb->pixel_format, 0))) {
set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL);
goto out_disable; goto out_disable;
} }
...@@ -948,7 +1015,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) ...@@ -948,7 +1015,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
*/ */
void intel_fbc_update(struct drm_i915_private *dev_priv) void intel_fbc_update(struct drm_i915_private *dev_priv)
{ {
if (!dev_priv->fbc.enable_fbc) if (!fbc_supported(dev_priv))
return; return;
mutex_lock(&dev_priv->fbc.lock); mutex_lock(&dev_priv->fbc.lock);
...@@ -962,7 +1029,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, ...@@ -962,7 +1029,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
{ {
unsigned int fbc_bits; unsigned int fbc_bits;
if (!dev_priv->fbc.enable_fbc) if (!fbc_supported(dev_priv))
return; return;
if (origin == ORIGIN_GTT) if (origin == ORIGIN_GTT)
...@@ -989,7 +1056,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, ...@@ -989,7 +1056,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
void intel_fbc_flush(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) unsigned int frontbuffer_bits, enum fb_op_origin origin)
{ {
if (!dev_priv->fbc.enable_fbc) if (!fbc_supported(dev_priv))
return; return;
if (origin == ORIGIN_GTT) if (origin == ORIGIN_GTT)
......
...@@ -121,8 +121,9 @@ static int intelfb_alloc(struct drm_fb_helper *helper, ...@@ -121,8 +121,9 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
container_of(helper, struct intel_fbdev, helper); container_of(helper, struct intel_fbdev, helper);
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_device *dev = helper->dev; struct drm_device *dev = helper->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_mode_fb_cmd2 mode_cmd = {};
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj = NULL;
int size, ret; int size, ret;
/* we don't do packed 24bpp */ /* we don't do packed 24bpp */
...@@ -139,6 +140,11 @@ static int intelfb_alloc(struct drm_fb_helper *helper, ...@@ -139,6 +140,11 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
size = mode_cmd.pitches[0] * mode_cmd.height; size = mode_cmd.pitches[0] * mode_cmd.height;
size = PAGE_ALIGN(size); size = PAGE_ALIGN(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); obj = i915_gem_object_create_stolen(dev, size);
if (obj == NULL) if (obj == NULL)
obj = i915_gem_alloc_object(dev, size); obj = i915_gem_alloc_object(dev, size);
......
...@@ -110,6 +110,8 @@ extern void intel_guc_ucode_init(struct drm_device *dev); ...@@ -110,6 +110,8 @@ extern void intel_guc_ucode_init(struct drm_device *dev);
extern int intel_guc_ucode_load(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 void intel_guc_ucode_fini(struct drm_device *dev);
extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status); 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 */ /* i915_guc_submission.c */
int i915_guc_submission_init(struct drm_device *dev); int i915_guc_submission_init(struct drm_device *dev);
......
...@@ -218,12 +218,23 @@ struct guc_context_desc { ...@@ -218,12 +218,23 @@ struct guc_context_desc {
u64 desc_private; u64 desc_private;
} __packed; } __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 */ /* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
enum host2guc_action { enum host2guc_action {
HOST2GUC_ACTION_DEFAULT = 0x0, HOST2GUC_ACTION_DEFAULT = 0x0,
HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6, HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6,
HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10, HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20, HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
HOST2GUC_ACTION_ENTER_S_STATE = 0x501,
HOST2GUC_ACTION_EXIT_S_STATE = 0x502,
HOST2GUC_ACTION_SLPC_REQUEST = 0x3003, HOST2GUC_ACTION_SLPC_REQUEST = 0x3003,
HOST2GUC_ACTION_LIMIT HOST2GUC_ACTION_LIMIT
}; };
......
...@@ -90,9 +90,6 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv) ...@@ -90,9 +90,6 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
for_each_ring(ring, dev_priv, i) for_each_ring(ring, dev_priv, i)
I915_WRITE(RING_MODE_GEN7(ring), irqs); I915_WRITE(RING_MODE_GEN7(ring), irqs);
/* tell DE to send nothing to GuC */
I915_WRITE(DE_GUCRMR, ~0);
/* route all GT interrupts to the host */ /* route all GT interrupts to the host */
I915_WRITE(GUC_BCS_RCS_IER, 0); I915_WRITE(GUC_BCS_RCS_IER, 0);
I915_WRITE(GUC_VCS2_VCS1_IER, 0); I915_WRITE(GUC_VCS2_VCS1_IER, 0);
...@@ -110,13 +107,6 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv) ...@@ -110,13 +107,6 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
for_each_ring(ring, dev_priv, i) for_each_ring(ring, dev_priv, i)
I915_WRITE(RING_MODE_GEN7(ring), irqs); I915_WRITE(RING_MODE_GEN7(ring), irqs);
/* tell DE to send (all) flip_done to GuC */
irqs = DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEA_SPR_FLIP_DONE |
DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEB_SPR_FLIP_DONE |
DERRMR_PIPEC_PRI_FLIP_DONE | DERRMR_PIPEC_SPR_FLIP_DONE;
/* Unmasked bits will cause GuC response message to be sent */
I915_WRITE(DE_GUCRMR, ~irqs);
/* route USER_INTERRUPT to Host, all others are sent to GuC. */ /* route USER_INTERRUPT to Host, all others are sent to GuC. */
irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
...@@ -209,9 +199,10 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv, ...@@ -209,9 +199,10 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
u32 *status) u32 *status)
{ {
u32 val = I915_READ(GUC_STATUS); u32 val = I915_READ(GUC_STATUS);
u32 uk_val = val & GS_UKERNEL_MASK;
*status = val; *status = val;
return ((val & GS_UKERNEL_MASK) == GS_UKERNEL_READY || return (uk_val == GS_UKERNEL_READY ||
(val & GS_UKERNEL_MASK) == GS_UKERNEL_LAPIC_DONE); ((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
} }
/* /*
...@@ -257,7 +248,7 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv) ...@@ -257,7 +248,7 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
/* Copy RSA signature from the fw image to HW for verification */ /* 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); 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++) for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]); I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
/* Set the source address for the new blob */ /* Set the source address for the new blob */
offset = i915_gem_obj_ggtt_offset(fw_obj); offset = i915_gem_obj_ggtt_offset(fw_obj);
...@@ -392,7 +383,6 @@ int intel_guc_ucode_load(struct drm_device *dev) ...@@ -392,7 +383,6 @@ int intel_guc_ucode_load(struct drm_device *dev)
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
direct_interrupts_to_host(dev_priv); direct_interrupts_to_host(dev_priv);
i915_guc_submission_disable(dev);
if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE) if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE)
return 0; return 0;
...@@ -442,6 +432,9 @@ int intel_guc_ucode_load(struct drm_device *dev) ...@@ -442,6 +432,9 @@ int intel_guc_ucode_load(struct drm_device *dev)
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
if (i915.enable_guc_submission) { 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); err = i915_guc_submission_enable(dev);
if (err) if (err)
goto fail; goto fail;
......
此差异已折叠。
...@@ -904,21 +904,6 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, ...@@ -904,21 +904,6 @@ int intel_execlists_submission(struct i915_execbuffer_params *params,
return -EINVAL; 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) { if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
DRM_DEBUG("sol reset is gen7 only\n"); DRM_DEBUG("sol reset is gen7 only\n");
return -EINVAL; return -EINVAL;
......
...@@ -139,8 +139,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder) ...@@ -139,8 +139,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
const struct drm_display_mode *adjusted_mode = const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
&crtc->config->base.adjusted_mode;
int pipe = crtc->pipe; int pipe = crtc->pipe;
u32 temp; u32 temp;
......
...@@ -126,3 +126,12 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) ...@@ -126,3 +126,12 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
drm_object_attach_property(&connector->base, prop, 0); 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);
}
...@@ -341,7 +341,11 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, ...@@ -341,7 +341,11 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
if (!HAS_DDI(dev)) if (!HAS_DDI(dev))
return 0; return 0;
if (intel_encoder->type == INTEL_OUTPUT_DSI)
port = 0;
else
port = intel_ddi_get_encoder_port(intel_encoder); port = intel_ddi_get_encoder_port(intel_encoder);
if (port == PORT_E) { if (port == PORT_E) {
port = 0; port = 0;
} else { } else {
...@@ -363,6 +367,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, ...@@ -363,6 +367,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL; type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
break; break;
case INTEL_OUTPUT_EDP: case INTEL_OUTPUT_EDP:
case INTEL_OUTPUT_DSI:
type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL; type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL;
break; break;
default: default:
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -690,7 +690,8 @@ struct drm_i915_gem_exec_object2 { ...@@ -690,7 +690,8 @@ struct drm_i915_gem_exec_object2 {
#define EXEC_OBJECT_NEEDS_FENCE (1<<0) #define EXEC_OBJECT_NEEDS_FENCE (1<<0)
#define EXEC_OBJECT_NEEDS_GTT (1<<1) #define EXEC_OBJECT_NEEDS_GTT (1<<1)
#define EXEC_OBJECT_WRITE (1<<2) #define EXEC_OBJECT_WRITE (1<<2)
#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_WRITE<<1) #define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_SUPPORTS_48B_ADDRESS<<1)
__u64 flags; __u64 flags;
__u64 rsvd1; __u64 rsvd1;
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册