Merge tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel into drm-next
- Inherit/reuse firmwar framebuffers (for real this time) from Jesse, less flicker for fastbooting. - More flexible cloning for hdmi (Ville). - Some PPGTT fixes from Ben. - Ring init fixes from Naresh Kumar. - set_cache_level regression fixes for the vma conversion from Ville&Chris. - Conversion to the new dp aux helpers (Jani). - Unification of runtime pm with pc8 support from Paulo, prep work for runtime pm on other platforms than HSW. - Larger cursor sizes (Sagar Kamble). - Piles of improvements and fixes all over, as usual. * tag 'drm-intel-next-2014-03-21' of git://anongit.freedesktop.org/drm-intel: (75 commits) drm/i915: Include a note about the dangers of I915_READ64/I915_WRITE64 drm/i915/sdvo: fix questionable return value check drm/i915: Fix unsafe loop iteration over vma whilst unbinding them drm/i915: Enabling 128x128 and 256x256 ARGB Cursor Support drm/i915: Print how many objects are shared in per-process stats drm/i915: Per-process stats work better when evaluated per-process drm/i915: remove rps local variables drm/i915: Remove extraneous MMIO for RPS drm/i915: Rename and comment all the RPS *stuff* drm/i915: Store the HW min frequency as min_freq drm/i915: Fix coding style for RPS drm/i915: Reorganize the overclock code drm/i915: init pm.suspended earlier drm/i915: update the PC8 and runtime PM documentation drm/i915: rename __hsw_do_{en, dis}able_pc8 drm/i915: kill struct i915_package_c8 drm/i915: move pc8.irqs_disabled to pm.irqs_disabled drm/i915: remove dev_priv->pc8.enabled drm/i915: don't get/put PC8 when getting/putting power wells drm/i915: make intel_aux_display_runtime_get get runtime PM, not PC8 ... Conflicts: drivers/gpu/drm/i915/intel_display.c drivers/gpu/drm/i915/intel_dp.c
This commit is contained in:
commit
66e514c14a
32 changed files with 1309 additions and 931 deletions
|
@ -726,7 +726,8 @@ int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux)
|
|||
aux->ddc.dev.parent = aux->dev;
|
||||
aux->ddc.dev.of_node = aux->dev->of_node;
|
||||
|
||||
strncpy(aux->ddc.name, dev_name(aux->dev), sizeof(aux->ddc.name));
|
||||
strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
|
||||
sizeof(aux->ddc.name));
|
||||
|
||||
return i2c_add_adapter(&aux->ddc);
|
||||
}
|
||||
|
|
|
@ -402,7 +402,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring,
|
|||
length = ((*cmd & desc->length.mask) + LENGTH_BIAS);
|
||||
|
||||
if ((batch_end - cmd) < length) {
|
||||
DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%ld\n",
|
||||
DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n",
|
||||
*cmd,
|
||||
length,
|
||||
(unsigned long)(batch_end - cmd));
|
||||
|
|
|
@ -299,28 +299,62 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
|
|||
} while (0)
|
||||
|
||||
struct file_stats {
|
||||
struct drm_i915_file_private *file_priv;
|
||||
int count;
|
||||
size_t total, active, inactive, unbound;
|
||||
size_t total, unbound;
|
||||
size_t global, shared;
|
||||
size_t active, inactive;
|
||||
};
|
||||
|
||||
static int per_file_stats(int id, void *ptr, void *data)
|
||||
{
|
||||
struct drm_i915_gem_object *obj = ptr;
|
||||
struct file_stats *stats = data;
|
||||
struct i915_vma *vma;
|
||||
|
||||
stats->count++;
|
||||
stats->total += obj->base.size;
|
||||
|
||||
if (i915_gem_obj_ggtt_bound(obj)) {
|
||||
if (!list_empty(&obj->ring_list))
|
||||
stats->active += obj->base.size;
|
||||
else
|
||||
stats->inactive += obj->base.size;
|
||||
if (obj->base.name || obj->base.dma_buf)
|
||||
stats->shared += obj->base.size;
|
||||
|
||||
if (USES_FULL_PPGTT(obj->base.dev)) {
|
||||
list_for_each_entry(vma, &obj->vma_list, vma_link) {
|
||||
struct i915_hw_ppgtt *ppgtt;
|
||||
|
||||
if (!drm_mm_node_allocated(&vma->node))
|
||||
continue;
|
||||
|
||||
if (i915_is_ggtt(vma->vm)) {
|
||||
stats->global += obj->base.size;
|
||||
continue;
|
||||
}
|
||||
|
||||
ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base);
|
||||
if (ppgtt->ctx && ppgtt->ctx->file_priv != stats->file_priv)
|
||||
continue;
|
||||
|
||||
if (obj->ring) /* XXX per-vma statistic */
|
||||
stats->active += obj->base.size;
|
||||
else
|
||||
stats->inactive += obj->base.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!list_empty(&obj->global_list))
|
||||
stats->unbound += obj->base.size;
|
||||
if (i915_gem_obj_ggtt_bound(obj)) {
|
||||
stats->global += obj->base.size;
|
||||
if (obj->ring)
|
||||
stats->active += obj->base.size;
|
||||
else
|
||||
stats->inactive += obj->base.size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_empty(&obj->global_list))
|
||||
stats->unbound += obj->base.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -411,6 +445,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
|
|||
struct task_struct *task;
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
stats.file_priv = file->driver_priv;
|
||||
idr_for_each(&file->object_idr, per_file_stats, &stats);
|
||||
/*
|
||||
* Although we have a valid reference on file->pid, that does
|
||||
|
@ -420,12 +455,14 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
|
|||
*/
|
||||
rcu_read_lock();
|
||||
task = pid_task(file->pid, PIDTYPE_PID);
|
||||
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n",
|
||||
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n",
|
||||
task ? task->comm : "<unknown>",
|
||||
stats.count,
|
||||
stats.total,
|
||||
stats.active,
|
||||
stats.inactive,
|
||||
stats.global,
|
||||
stats.shared,
|
||||
stats.unbound);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
@ -1026,7 +1063,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
|||
max_freq * GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
seq_printf(m, "Max overclocked frequency: %dMHz\n",
|
||||
dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
|
||||
dev_priv->rps.max_freq * GT_FREQUENCY_MULTIPLIER);
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
u32 freq_sts, val;
|
||||
|
||||
|
@ -1498,8 +1535,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
|
|||
|
||||
seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
|
||||
|
||||
for (gpu_freq = dev_priv->rps.min_delay;
|
||||
gpu_freq <= dev_priv->rps.max_delay;
|
||||
for (gpu_freq = dev_priv->rps.min_freq_softlimit;
|
||||
gpu_freq <= dev_priv->rps.max_freq_softlimit;
|
||||
gpu_freq++) {
|
||||
ia_freq = gpu_freq;
|
||||
sandybridge_pcode_read(dev_priv,
|
||||
|
@ -2012,15 +2049,9 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
|
|||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&dev_priv->pc8.lock);
|
||||
seq_printf(m, "Requirements met: %s\n",
|
||||
yesno(dev_priv->pc8.requirements_met));
|
||||
seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy));
|
||||
seq_printf(m, "Disable count: %d\n", dev_priv->pc8.disable_count);
|
||||
seq_printf(m, "IRQs disabled: %s\n",
|
||||
yesno(dev_priv->pc8.irqs_disabled));
|
||||
seq_printf(m, "Enabled: %s\n", yesno(dev_priv->pc8.enabled));
|
||||
mutex_unlock(&dev_priv->pc8.lock);
|
||||
yesno(dev_priv->pm.irqs_disabled));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2248,24 +2279,67 @@ static void intel_connector_info(struct seq_file *m,
|
|||
intel_seq_print_mode(m, 2, mode);
|
||||
}
|
||||
|
||||
static bool cursor_active(struct drm_device *dev, int pipe)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 state;
|
||||
|
||||
if (IS_845G(dev) || IS_I865G(dev))
|
||||
state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
|
||||
else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
|
||||
state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
|
||||
else
|
||||
state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pos;
|
||||
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
|
||||
pos = I915_READ(CURPOS_IVB(pipe));
|
||||
else
|
||||
pos = I915_READ(CURPOS(pipe));
|
||||
|
||||
*x = (pos >> CURSOR_X_SHIFT) & CURSOR_POS_MASK;
|
||||
if (pos & (CURSOR_POS_SIGN << CURSOR_X_SHIFT))
|
||||
*x = -*x;
|
||||
|
||||
*y = (pos >> CURSOR_Y_SHIFT) & CURSOR_POS_MASK;
|
||||
if (pos & (CURSOR_POS_SIGN << CURSOR_Y_SHIFT))
|
||||
*y = -*y;
|
||||
|
||||
return cursor_active(dev, pipe);
|
||||
}
|
||||
|
||||
static int i915_display_info(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct intel_crtc *crtc;
|
||||
struct drm_connector *connector;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
seq_printf(m, "CRTC info\n");
|
||||
seq_printf(m, "---------\n");
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
|
||||
bool active;
|
||||
int x, y;
|
||||
|
||||
seq_printf(m, "CRTC %d: pipe: %c, active: %s\n",
|
||||
crtc->base.id, pipe_name(intel_crtc->pipe),
|
||||
intel_crtc->active ? "yes" : "no");
|
||||
if (intel_crtc->active)
|
||||
intel_crtc_info(m, intel_crtc);
|
||||
crtc->base.base.id, pipe_name(crtc->pipe),
|
||||
yesno(crtc->active));
|
||||
if (crtc->active)
|
||||
intel_crtc_info(m, crtc);
|
||||
|
||||
active = cursor_position(dev, crtc->pipe, &x, &y);
|
||||
seq_printf(m, "\tcursor visible? %s, position (%d, %d), addr 0x%08x, active? %s\n",
|
||||
yesno(crtc->cursor_visible),
|
||||
x, y, crtc->cursor_addr,
|
||||
yesno(active));
|
||||
}
|
||||
|
||||
seq_printf(m, "\n");
|
||||
|
@ -2603,8 +2677,6 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
|
|||
if (need_stable_symbols) {
|
||||
uint32_t tmp = I915_READ(PORT_DFT2_G4X);
|
||||
|
||||
WARN_ON(!IS_G4X(dev));
|
||||
|
||||
tmp |= DC_BALANCE_RESET_VLV;
|
||||
if (pipe == PIPE_A)
|
||||
tmp |= PIPE_A_SCRAMBLE_RESET;
|
||||
|
@ -3414,9 +3486,9 @@ i915_max_freq_get(void *data, u64 *val)
|
|||
return ret;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
*val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
|
||||
*val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
|
||||
else
|
||||
*val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
*val = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -3453,16 +3525,16 @@ i915_max_freq_set(void *data, u64 val)
|
|||
do_div(val, GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
hw_max = dev_priv->rps.hw_max;
|
||||
hw_max = dev_priv->rps.max_freq;
|
||||
hw_min = (rp_state_cap >> 16) & 0xff;
|
||||
}
|
||||
|
||||
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
|
||||
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_freq_softlimit) {
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->rps.max_delay = val;
|
||||
dev_priv->rps.max_freq_softlimit = val;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev, val);
|
||||
|
@ -3495,9 +3567,9 @@ i915_min_freq_get(void *data, u64 *val)
|
|||
return ret;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
*val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
|
||||
*val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
|
||||
else
|
||||
*val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
*val = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -3534,16 +3606,16 @@ i915_min_freq_set(void *data, u64 val)
|
|||
do_div(val, GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
hw_max = dev_priv->rps.hw_max;
|
||||
hw_max = dev_priv->rps.max_freq;
|
||||
hw_min = (rp_state_cap >> 16) & 0xff;
|
||||
}
|
||||
|
||||
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
|
||||
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->rps.min_delay = val;
|
||||
dev_priv->rps.min_freq_softlimit = val;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev, val);
|
||||
|
|
|
@ -1187,6 +1187,9 @@ intel_setup_mchbar(struct drm_device *dev)
|
|||
u32 temp;
|
||||
bool enabled;
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
return;
|
||||
|
||||
dev_priv->mchbar_need_disable = false;
|
||||
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
|
@ -1608,8 +1611,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
goto put_bridge;
|
||||
}
|
||||
|
||||
intel_uncore_early_sanitize(dev);
|
||||
|
||||
/* This must be called before any calls to HAS_PCH_* */
|
||||
intel_detect_pch(dev);
|
||||
|
||||
|
@ -1822,8 +1823,6 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
cancel_work_sync(&dev_priv->gpu_error.work);
|
||||
i915_destroy_error_state(dev);
|
||||
|
||||
cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
|
||||
|
||||
if (dev->pdev->msi_enabled)
|
||||
pci_disable_msi(dev->pdev);
|
||||
|
||||
|
|
|
@ -428,7 +428,6 @@ static int i915_drm_freeze(struct drm_device *dev)
|
|||
|
||||
/* We do a lot of poking in a lot of registers, make sure they work
|
||||
* properly. */
|
||||
hsw_disable_package_c8(dev_priv);
|
||||
intel_display_set_init_power(dev_priv, true);
|
||||
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
@ -467,6 +466,7 @@ static int i915_drm_freeze(struct drm_device *dev)
|
|||
i915_save_state(dev);
|
||||
|
||||
intel_opregion_fini(dev);
|
||||
intel_uncore_fini(dev);
|
||||
|
||||
console_lock();
|
||||
intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
|
||||
|
@ -603,10 +603,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
|
|||
schedule_work(&dev_priv->console_resume_work);
|
||||
}
|
||||
|
||||
/* Undo what we did at i915_drm_freeze so the refcount goes back to the
|
||||
* expected level. */
|
||||
hsw_enable_package_c8(dev_priv);
|
||||
|
||||
mutex_lock(&dev_priv->modeset_restore_lock);
|
||||
dev_priv->modeset_restore = MODESET_DONE;
|
||||
mutex_unlock(&dev_priv->modeset_restore_lock);
|
||||
|
@ -848,6 +844,9 @@ static int i915_runtime_suspend(struct device *device)
|
|||
|
||||
DRM_DEBUG_KMS("Suspending device\n");
|
||||
|
||||
if (HAS_PC8(dev))
|
||||
hsw_enable_pc8(dev_priv);
|
||||
|
||||
i915_gem_release_all_mmaps(dev_priv);
|
||||
|
||||
del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
|
||||
|
@ -862,6 +861,7 @@ static int i915_runtime_suspend(struct device *device)
|
|||
*/
|
||||
intel_opregion_notify_adapter(dev, PCI_D1);
|
||||
|
||||
DRM_DEBUG_KMS("Device suspended\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -878,6 +878,10 @@ static int i915_runtime_resume(struct device *device)
|
|||
intel_opregion_notify_adapter(dev, PCI_D0);
|
||||
dev_priv->pm.suspended = false;
|
||||
|
||||
if (HAS_PC8(dev))
|
||||
hsw_disable_pc8(dev_priv);
|
||||
|
||||
DRM_DEBUG_KMS("Device resumed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -406,6 +406,7 @@ struct drm_i915_error_state {
|
|||
|
||||
struct intel_connector;
|
||||
struct intel_crtc_config;
|
||||
struct intel_plane_config;
|
||||
struct intel_crtc;
|
||||
struct intel_limit;
|
||||
struct dpll;
|
||||
|
@ -444,6 +445,8 @@ struct drm_i915_display_funcs {
|
|||
* fills out the pipe-config with the hw state. */
|
||||
bool (*get_pipe_config)(struct intel_crtc *,
|
||||
struct intel_crtc_config *);
|
||||
void (*get_plane_config)(struct intel_crtc *,
|
||||
struct intel_plane_config *);
|
||||
int (*crtc_mode_set)(struct drm_crtc *crtc,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb);
|
||||
|
@ -459,8 +462,9 @@ struct drm_i915_display_funcs {
|
|||
struct drm_framebuffer *fb,
|
||||
struct drm_i915_gem_object *obj,
|
||||
uint32_t flags);
|
||||
int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y);
|
||||
int (*update_primary_plane)(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
int x, int y);
|
||||
void (*hpd_irq_setup)(struct drm_device *dev);
|
||||
/* clock updates for mode set */
|
||||
/* cursor updates */
|
||||
|
@ -721,6 +725,8 @@ struct i915_hw_ppgtt {
|
|||
dma_addr_t *gen8_pt_dma_addr[4];
|
||||
};
|
||||
|
||||
struct i915_hw_context *ctx;
|
||||
|
||||
int (*enable)(struct i915_hw_ppgtt *ppgtt);
|
||||
int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
|
||||
struct intel_ring_buffer *ring,
|
||||
|
@ -976,13 +982,24 @@ struct intel_gen6_power_mgmt {
|
|||
struct work_struct work;
|
||||
u32 pm_iir;
|
||||
|
||||
u8 cur_delay;
|
||||
u8 min_delay;
|
||||
u8 max_delay;
|
||||
u8 rpe_delay;
|
||||
u8 rp1_delay;
|
||||
u8 rp0_delay;
|
||||
u8 hw_max;
|
||||
/* Frequencies are stored in potentially platform dependent multiples.
|
||||
* In other words, *_freq needs to be multiplied by X to be interesting.
|
||||
* Soft limits are those which are used for the dynamic reclocking done
|
||||
* by the driver (raise frequencies under heavy loads, and lower for
|
||||
* lighter loads). Hard limits are those imposed by the hardware.
|
||||
*
|
||||
* A distinction is made for overclocking, which is never enabled by
|
||||
* default, and is considered to be above the hard limit if it's
|
||||
* possible at all.
|
||||
*/
|
||||
u8 cur_freq; /* Current frequency (cached, may not == HW) */
|
||||
u8 min_freq_softlimit; /* Minimum frequency permitted by the driver */
|
||||
u8 max_freq_softlimit; /* Max frequency permitted by the driver */
|
||||
u8 max_freq; /* Maximum frequency, RP0 if not overclocking */
|
||||
u8 min_freq; /* AKA RPn. Minimum frequency */
|
||||
u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */
|
||||
u8 rp1_freq; /* "less than" RP0 power/freqency */
|
||||
u8 rp0_freq; /* Non-overclocked max frequency. */
|
||||
|
||||
bool rp_up_masked;
|
||||
bool rp_down_masked;
|
||||
|
@ -1333,43 +1350,19 @@ struct ilk_wm_values {
|
|||
};
|
||||
|
||||
/*
|
||||
* This struct tracks the state needed for the Package C8+ feature.
|
||||
* This struct helps tracking the state needed for runtime PM, which puts the
|
||||
* device in PCI D3 state. Notice that when this happens, nothing on the
|
||||
* graphics device works, even register access, so we don't get interrupts nor
|
||||
* anything else.
|
||||
*
|
||||
* Package states C8 and deeper are really deep PC states that can only be
|
||||
* reached when all the devices on the system allow it, so even if the graphics
|
||||
* device allows PC8+, it doesn't mean the system will actually get to these
|
||||
* states.
|
||||
* Every piece of our code that needs to actually touch the hardware needs to
|
||||
* either call intel_runtime_pm_get or call intel_display_power_get with the
|
||||
* appropriate power domain.
|
||||
*
|
||||
* Our driver only allows PC8+ when all the outputs are disabled, the power well
|
||||
* is disabled and the GPU is idle. When these conditions are met, we manually
|
||||
* do the other conditions: disable the interrupts, clocks and switch LCPLL
|
||||
* refclk to Fclk.
|
||||
*
|
||||
* When we really reach PC8 or deeper states (not just when we allow it) we lose
|
||||
* the state of some registers, so when we come back from PC8+ we need to
|
||||
* restore this state. We don't get into PC8+ if we're not in RC6, so we don't
|
||||
* need to take care of the registers kept by RC6.
|
||||
*
|
||||
* The interrupt disabling is part of the requirements. We can only leave the
|
||||
* PCH HPD interrupts enabled. If we're in PC8+ and we get another interrupt we
|
||||
* can lock the machine.
|
||||
*
|
||||
* Ideally every piece of our code that needs PC8+ disabled would call
|
||||
* hsw_disable_package_c8, which would increment disable_count and prevent the
|
||||
* system from reaching PC8+. But we don't have a symmetric way to do this for
|
||||
* everything, so we have the requirements_met variable. When we switch
|
||||
* requirements_met to true we decrease disable_count, and increase it in the
|
||||
* opposite case. The requirements_met variable is true when all the CRTCs,
|
||||
* encoders and the power well are disabled.
|
||||
*
|
||||
* In addition to everything, we only actually enable PC8+ if disable_count
|
||||
* stays at zero for at least some seconds. This is implemented with the
|
||||
* enable_work variable. We do this so we don't enable/disable PC8 dozens of
|
||||
* consecutive times when all screens are disabled and some background app
|
||||
* queries the state of our connectors, or we have some application constantly
|
||||
* waking up to use the GPU. Only after the enable_work function actually
|
||||
* enables PC8+ the "enable" variable will become true, which means that it can
|
||||
* be false even if disable_count is 0.
|
||||
* Our driver uses the autosuspend delay feature, which means we'll only really
|
||||
* suspend if we stay with zero refcount for a certain amount of time. The
|
||||
* default value is currently very conservative (see intel_init_runtime_pm), but
|
||||
* it can be changed with the standard runtime PM files from sysfs.
|
||||
*
|
||||
* The irqs_disabled variable becomes true exactly after we disable the IRQs and
|
||||
* goes back to false exactly before we reenable the IRQs. We use this variable
|
||||
|
@ -1379,16 +1372,11 @@ struct ilk_wm_values {
|
|||
* inside struct regsave so when we restore the IRQs they will contain the
|
||||
* latest expected values.
|
||||
*
|
||||
* For more, read "Display Sequences for Package C8" on our documentation.
|
||||
* For more, read the Documentation/power/runtime_pm.txt.
|
||||
*/
|
||||
struct i915_package_c8 {
|
||||
bool requirements_met;
|
||||
struct i915_runtime_pm {
|
||||
bool suspended;
|
||||
bool irqs_disabled;
|
||||
/* Only true after the delayed work task actually enables it. */
|
||||
bool enabled;
|
||||
int disable_count;
|
||||
struct mutex lock;
|
||||
struct delayed_work enable_work;
|
||||
|
||||
struct {
|
||||
uint32_t deimr;
|
||||
|
@ -1399,10 +1387,6 @@ struct i915_package_c8 {
|
|||
} regsave;
|
||||
};
|
||||
|
||||
struct i915_runtime_pm {
|
||||
bool suspended;
|
||||
};
|
||||
|
||||
enum intel_pipe_crc_source {
|
||||
INTEL_PIPE_CRC_SOURCE_NONE,
|
||||
INTEL_PIPE_CRC_SOURCE_PLANE1,
|
||||
|
@ -1610,6 +1594,7 @@ typedef struct drm_i915_private {
|
|||
|
||||
u32 fdi_rx_config;
|
||||
|
||||
u32 suspend_count;
|
||||
struct i915_suspend_saved_registers regfile;
|
||||
|
||||
struct {
|
||||
|
@ -1629,8 +1614,6 @@ typedef struct drm_i915_private {
|
|||
struct ilk_wm_values hw;
|
||||
} wm;
|
||||
|
||||
struct i915_package_c8 pc8;
|
||||
|
||||
struct i915_runtime_pm pm;
|
||||
|
||||
/* Old dri1 support infrastructure, beware the dragons ya fools entering
|
||||
|
@ -1638,8 +1621,6 @@ typedef struct drm_i915_private {
|
|||
struct i915_dri1_state dri1;
|
||||
/* Old ums support infrastructure, same warning applies. */
|
||||
struct i915_ums_state ums;
|
||||
|
||||
u32 suspend_count;
|
||||
} drm_i915_private_t;
|
||||
|
||||
static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
|
||||
|
@ -2092,8 +2073,6 @@ struct i915_params {
|
|||
unsigned int preliminary_hw_support;
|
||||
int disable_power_well;
|
||||
int enable_ips;
|
||||
int enable_pc8;
|
||||
int pc8_timeout;
|
||||
int invert_brightness;
|
||||
int enable_cmd_parser;
|
||||
/* leave bools at the end to not create holes */
|
||||
|
@ -2757,6 +2736,12 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
|
|||
#define I915_READ_NOTRACE(reg) dev_priv->uncore.funcs.mmio_readl(dev_priv, (reg), false)
|
||||
#define I915_WRITE_NOTRACE(reg, val) dev_priv->uncore.funcs.mmio_writel(dev_priv, (reg), (val), false)
|
||||
|
||||
/* Be very careful with read/write 64-bit values. On 32-bit machines, they
|
||||
* will be implemented using 2 32-bit writes in an arbitrary order with
|
||||
* an arbitrary delay between them. This can cause the hardware to
|
||||
* act upon the intermediate value, possibly leading to corruption and
|
||||
* machine death. You have been warned.
|
||||
*/
|
||||
#define I915_WRITE64(reg, val) dev_priv->uncore.funcs.mmio_writeq(dev_priv, (reg), (val), true)
|
||||
#define I915_READ64(reg) dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
|
||||
|
||||
|
|
|
@ -510,12 +510,10 @@ i915_gem_shmem_pread(struct drm_device *dev,
|
|||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
next_page:
|
||||
mark_page_accessed(page);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
next_page:
|
||||
remain -= page_length;
|
||||
user_data += page_length;
|
||||
offset += page_length;
|
||||
|
@ -695,9 +693,8 @@ shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length,
|
|||
if (needs_clflush_before)
|
||||
drm_clflush_virt_range(vaddr + shmem_page_offset,
|
||||
page_length);
|
||||
ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset,
|
||||
user_data,
|
||||
page_length);
|
||||
ret = __copy_from_user_inatomic(vaddr + shmem_page_offset,
|
||||
user_data, page_length);
|
||||
if (needs_clflush_after)
|
||||
drm_clflush_virt_range(vaddr + shmem_page_offset,
|
||||
page_length);
|
||||
|
@ -831,13 +828,10 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
|
|||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
next_page:
|
||||
set_page_dirty(page);
|
||||
mark_page_accessed(page);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
next_page:
|
||||
remain -= page_length;
|
||||
user_data += page_length;
|
||||
offset += page_length;
|
||||
|
@ -1041,7 +1035,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
|
|||
unsigned long timeout_expire;
|
||||
int ret;
|
||||
|
||||
WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n");
|
||||
WARN(dev_priv->pm.irqs_disabled, "IRQs disabled\n");
|
||||
|
||||
if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
|
||||
return 0;
|
||||
|
@ -3473,7 +3467,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
|
|||
enum i915_cache_level cache_level)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct i915_vma *vma;
|
||||
struct i915_vma *vma, *next;
|
||||
int ret;
|
||||
|
||||
if (obj->cache_level == cache_level)
|
||||
|
@ -3484,13 +3478,11 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
list_for_each_entry(vma, &obj->vma_list, vma_link) {
|
||||
list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
|
||||
if (!i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) {
|
||||
ret = i915_vma_unbind(vma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -215,6 +215,7 @@ create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx)
|
|||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
ppgtt->ctx = ctx;
|
||||
return ppgtt;
|
||||
}
|
||||
|
||||
|
@ -775,9 +776,11 @@ int i915_switch_context(struct intel_ring_buffer *ring,
|
|||
|
||||
BUG_ON(file && to == NULL);
|
||||
|
||||
/* We have the fake context, but don't supports switching. */
|
||||
if (!HAS_HW_CONTEXTS(ring->dev))
|
||||
/* We have the fake context */
|
||||
if (!HAS_HW_CONTEXTS(ring->dev)) {
|
||||
ring->last_context = to;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return do_switch(ring, to);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "i915_trace.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv);
|
||||
|
||||
bool intel_enable_ppgtt(struct drm_device *dev, bool full)
|
||||
{
|
||||
if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
|
||||
|
@ -1191,9 +1193,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
|
|||
ppgtt->base.clear_range = gen6_ppgtt_clear_range;
|
||||
ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
|
||||
ppgtt->base.cleanup = gen6_ppgtt_cleanup;
|
||||
ppgtt->base.scratch = dev_priv->gtt.base.scratch;
|
||||
ppgtt->base.start = 0;
|
||||
ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
|
||||
ppgtt->base.total = ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
|
||||
ppgtt->debug_dump = gen6_dump_ppgtt;
|
||||
|
||||
ppgtt->pd_offset =
|
||||
|
@ -1214,6 +1215,7 @@ int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
|
|||
int ret = 0;
|
||||
|
||||
ppgtt->base.dev = dev;
|
||||
ppgtt->base.scratch = dev_priv->gtt.base.scratch;
|
||||
|
||||
if (INTEL_INFO(dev)->gen < 8)
|
||||
ret = gen6_ppgtt_init(ppgtt);
|
||||
|
@ -1243,8 +1245,6 @@ ppgtt_bind_vma(struct i915_vma *vma,
|
|||
enum i915_cache_level cache_level,
|
||||
u32 flags)
|
||||
{
|
||||
WARN_ON(flags);
|
||||
|
||||
vma->vm->insert_entries(vma->vm, vma->obj->pages, vma->node.start,
|
||||
cache_level);
|
||||
}
|
||||
|
@ -1372,8 +1372,10 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
|||
}
|
||||
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 8)
|
||||
if (INTEL_INFO(dev)->gen >= 8) {
|
||||
gen8_setup_private_ppat(dev_priv);
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
|
||||
/* TODO: Perhaps it shouldn't be gen6 specific */
|
||||
|
|
|
@ -850,10 +850,12 @@ static void i915_record_ring_state(struct drm_device *dev,
|
|||
}
|
||||
break;
|
||||
case 7:
|
||||
ering->vm_info.pp_dir_base = RING_PP_DIR_BASE(ring);
|
||||
ering->vm_info.pp_dir_base =
|
||||
I915_READ(RING_PP_DIR_BASE(ring));
|
||||
break;
|
||||
case 6:
|
||||
ering->vm_info.pp_dir_base = RING_PP_DIR_BASE_READ(ring);
|
||||
ering->vm_info.pp_dir_base =
|
||||
I915_READ(RING_PP_DIR_BASE_READ(ring));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,9 +86,9 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
|
|||
{
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
if (dev_priv->pc8.irqs_disabled) {
|
||||
if (dev_priv->pm.irqs_disabled) {
|
||||
WARN(1, "IRQs disabled\n");
|
||||
dev_priv->pc8.regsave.deimr &= ~mask;
|
||||
dev_priv->pm.regsave.deimr &= ~mask;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -104,9 +104,9 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
|
|||
{
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
if (dev_priv->pc8.irqs_disabled) {
|
||||
if (dev_priv->pm.irqs_disabled) {
|
||||
WARN(1, "IRQs disabled\n");
|
||||
dev_priv->pc8.regsave.deimr |= mask;
|
||||
dev_priv->pm.regsave.deimr |= mask;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -129,10 +129,10 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
|
|||
{
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
if (dev_priv->pc8.irqs_disabled) {
|
||||
if (dev_priv->pm.irqs_disabled) {
|
||||
WARN(1, "IRQs disabled\n");
|
||||
dev_priv->pc8.regsave.gtimr &= ~interrupt_mask;
|
||||
dev_priv->pc8.regsave.gtimr |= (~enabled_irq_mask &
|
||||
dev_priv->pm.regsave.gtimr &= ~interrupt_mask;
|
||||
dev_priv->pm.regsave.gtimr |= (~enabled_irq_mask &
|
||||
interrupt_mask);
|
||||
return;
|
||||
}
|
||||
|
@ -167,10 +167,10 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
|
|||
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
if (dev_priv->pc8.irqs_disabled) {
|
||||
if (dev_priv->pm.irqs_disabled) {
|
||||
WARN(1, "IRQs disabled\n");
|
||||
dev_priv->pc8.regsave.gen6_pmimr &= ~interrupt_mask;
|
||||
dev_priv->pc8.regsave.gen6_pmimr |= (~enabled_irq_mask &
|
||||
dev_priv->pm.regsave.gen6_pmimr &= ~interrupt_mask;
|
||||
dev_priv->pm.regsave.gen6_pmimr |= (~enabled_irq_mask &
|
||||
interrupt_mask);
|
||||
return;
|
||||
}
|
||||
|
@ -313,11 +313,11 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
|
|||
|
||||
assert_spin_locked(&dev_priv->irq_lock);
|
||||
|
||||
if (dev_priv->pc8.irqs_disabled &&
|
||||
if (dev_priv->pm.irqs_disabled &&
|
||||
(interrupt_mask & SDE_HOTPLUG_MASK_CPT)) {
|
||||
WARN(1, "IRQs disabled\n");
|
||||
dev_priv->pc8.regsave.sdeimr &= ~interrupt_mask;
|
||||
dev_priv->pc8.regsave.sdeimr |= (~enabled_irq_mask &
|
||||
dev_priv->pm.regsave.sdeimr &= ~interrupt_mask;
|
||||
dev_priv->pm.regsave.sdeimr |= (~enabled_irq_mask &
|
||||
interrupt_mask);
|
||||
return;
|
||||
}
|
||||
|
@ -1075,7 +1075,7 @@ void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
|
|||
u32 pm_iir, int new_delay)
|
||||
{
|
||||
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
|
||||
if (new_delay >= dev_priv->rps.max_delay) {
|
||||
if (new_delay >= dev_priv->rps.max_freq_softlimit) {
|
||||
/* Mask UP THRESHOLD Interrupts */
|
||||
I915_WRITE(GEN6_PMINTRMSK,
|
||||
I915_READ(GEN6_PMINTRMSK) |
|
||||
|
@ -1090,7 +1090,7 @@ void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
|
|||
dev_priv->rps.rp_down_masked = false;
|
||||
}
|
||||
} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
|
||||
if (new_delay <= dev_priv->rps.min_delay) {
|
||||
if (new_delay <= dev_priv->rps.min_freq_softlimit) {
|
||||
/* Mask DOWN THRESHOLD Interrupts */
|
||||
I915_WRITE(GEN6_PMINTRMSK,
|
||||
I915_READ(GEN6_PMINTRMSK) |
|
||||
|
@ -1136,38 +1136,39 @@ static void gen6_pm_rps_work(struct work_struct *work)
|
|||
adj *= 2;
|
||||
else
|
||||
adj = 1;
|
||||
new_delay = dev_priv->rps.cur_delay + adj;
|
||||
new_delay = dev_priv->rps.cur_freq + adj;
|
||||
|
||||
/*
|
||||
* For better performance, jump directly
|
||||
* to RPe if we're below it.
|
||||
*/
|
||||
if (new_delay < dev_priv->rps.rpe_delay)
|
||||
new_delay = dev_priv->rps.rpe_delay;
|
||||
if (new_delay < dev_priv->rps.efficient_freq)
|
||||
new_delay = dev_priv->rps.efficient_freq;
|
||||
} else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
|
||||
if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay)
|
||||
new_delay = dev_priv->rps.rpe_delay;
|
||||
if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq)
|
||||
new_delay = dev_priv->rps.efficient_freq;
|
||||
else
|
||||
new_delay = dev_priv->rps.min_delay;
|
||||
new_delay = dev_priv->rps.min_freq_softlimit;
|
||||
adj = 0;
|
||||
} else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
|
||||
if (adj < 0)
|
||||
adj *= 2;
|
||||
else
|
||||
adj = -1;
|
||||
new_delay = dev_priv->rps.cur_delay + adj;
|
||||
new_delay = dev_priv->rps.cur_freq + adj;
|
||||
} else { /* unknown event */
|
||||
new_delay = dev_priv->rps.cur_delay;
|
||||
new_delay = dev_priv->rps.cur_freq;
|
||||
}
|
||||
|
||||
/* sysfs frequency interfaces may have snuck in while servicing the
|
||||
* interrupt
|
||||
*/
|
||||
new_delay = clamp_t(int, new_delay,
|
||||
dev_priv->rps.min_delay, dev_priv->rps.max_delay);
|
||||
dev_priv->rps.min_freq_softlimit,
|
||||
dev_priv->rps.max_freq_softlimit);
|
||||
|
||||
gen6_set_pm_mask(dev_priv, pm_iir, new_delay);
|
||||
dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
|
||||
dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq;
|
||||
|
||||
if (IS_VALLEYVIEW(dev_priv->dev))
|
||||
valleyview_set_rps(dev_priv->dev, new_delay);
|
||||
|
@ -3074,7 +3075,7 @@ static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv)
|
|||
|
||||
iir_mask = I915_DISPLAY_PORT_INTERRUPT |
|
||||
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
||||
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
|
||||
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
|
||||
|
||||
dev_priv->irq_mask |= iir_mask;
|
||||
I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
|
||||
|
@ -4118,32 +4119,32 @@ void intel_hpd_init(struct drm_device *dev)
|
|||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
}
|
||||
|
||||
/* Disable interrupts so we can allow Package C8+. */
|
||||
void hsw_pc8_disable_interrupts(struct drm_device *dev)
|
||||
/* Disable interrupts so we can allow runtime PM. */
|
||||
void hsw_runtime_pm_disable_interrupts(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
|
||||
|
||||
dev_priv->pc8.regsave.deimr = I915_READ(DEIMR);
|
||||
dev_priv->pc8.regsave.sdeimr = I915_READ(SDEIMR);
|
||||
dev_priv->pc8.regsave.gtimr = I915_READ(GTIMR);
|
||||
dev_priv->pc8.regsave.gtier = I915_READ(GTIER);
|
||||
dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
|
||||
dev_priv->pm.regsave.deimr = I915_READ(DEIMR);
|
||||
dev_priv->pm.regsave.sdeimr = I915_READ(SDEIMR);
|
||||
dev_priv->pm.regsave.gtimr = I915_READ(GTIMR);
|
||||
dev_priv->pm.regsave.gtier = I915_READ(GTIER);
|
||||
dev_priv->pm.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
|
||||
|
||||
ironlake_disable_display_irq(dev_priv, 0xffffffff);
|
||||
ibx_disable_display_interrupt(dev_priv, 0xffffffff);
|
||||
ilk_disable_gt_irq(dev_priv, 0xffffffff);
|
||||
snb_disable_pm_irq(dev_priv, 0xffffffff);
|
||||
|
||||
dev_priv->pc8.irqs_disabled = true;
|
||||
dev_priv->pm.irqs_disabled = true;
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
}
|
||||
|
||||
/* Restore interrupts so we can recover from Package C8+. */
|
||||
void hsw_pc8_restore_interrupts(struct drm_device *dev)
|
||||
/* Restore interrupts so we can recover from runtime PM. */
|
||||
void hsw_runtime_pm_restore_interrupts(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
@ -4163,13 +4164,13 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev)
|
|||
val = I915_READ(GEN6_PMIMR);
|
||||
WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
|
||||
|
||||
dev_priv->pc8.irqs_disabled = false;
|
||||
dev_priv->pm.irqs_disabled = false;
|
||||
|
||||
ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr);
|
||||
ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr);
|
||||
ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr);
|
||||
snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr);
|
||||
I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier);
|
||||
ironlake_enable_display_irq(dev_priv, ~dev_priv->pm.regsave.deimr);
|
||||
ibx_enable_display_interrupt(dev_priv, ~dev_priv->pm.regsave.sdeimr);
|
||||
ilk_enable_gt_irq(dev_priv, ~dev_priv->pm.regsave.gtimr);
|
||||
snb_enable_pm_irq(dev_priv, ~dev_priv->pm.regsave.gen6_pmimr);
|
||||
I915_WRITE(GTIER, dev_priv->pm.regsave.gtier);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
}
|
||||
|
|
|
@ -42,8 +42,6 @@ struct i915_params i915 __read_mostly = {
|
|||
.disable_power_well = 1,
|
||||
.enable_ips = 1,
|
||||
.fastboot = 0,
|
||||
.enable_pc8 = 1,
|
||||
.pc8_timeout = 5000,
|
||||
.prefault_disable = 0,
|
||||
.reset = true,
|
||||
.invert_brightness = 0,
|
||||
|
@ -135,14 +133,6 @@ module_param_named(fastboot, i915.fastboot, bool, 0600);
|
|||
MODULE_PARM_DESC(fastboot,
|
||||
"Try to skip unnecessary mode sets at boot time (default: false)");
|
||||
|
||||
module_param_named(enable_pc8, i915.enable_pc8, int, 0600);
|
||||
MODULE_PARM_DESC(enable_pc8,
|
||||
"Enable support for low power package C states (PC8+) (default: true)");
|
||||
|
||||
module_param_named(pc8_timeout, i915.pc8_timeout, int, 0600);
|
||||
MODULE_PARM_DESC(pc8_timeout,
|
||||
"Number of msecs of idleness required to enter PC8+ (default: 5000)");
|
||||
|
||||
module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
|
||||
MODULE_PARM_DESC(prefault_disable,
|
||||
"Disable page prefaulting for pread/pwrite/reloc (default:false). "
|
||||
|
|
|
@ -748,6 +748,7 @@ enum punit_power_well {
|
|||
#define RING_INSTPS(base) ((base)+0x70)
|
||||
#define RING_DMA_FADD(base) ((base)+0x78)
|
||||
#define RING_INSTPM(base) ((base)+0xc0)
|
||||
#define RING_MI_MODE(base) ((base)+0x9c)
|
||||
#define INSTPS 0x02070 /* 965+ only */
|
||||
#define INSTDONE1 0x0207c /* 965+ only */
|
||||
#define ACTHD_I965 0x02074
|
||||
|
@ -824,6 +825,7 @@ enum punit_power_well {
|
|||
# define VS_TIMER_DISPATCH (1 << 6)
|
||||
# define MI_FLUSH_ENABLE (1 << 12)
|
||||
# define ASYNC_FLIP_PERF_DISABLE (1 << 14)
|
||||
# define MODE_IDLE (1 << 9)
|
||||
|
||||
#define GEN6_GT_MODE 0x20d0
|
||||
#define GEN7_GT_MODE 0x7008
|
||||
|
@ -3551,7 +3553,11 @@ enum punit_power_well {
|
|||
/* New style CUR*CNTR flags */
|
||||
#define CURSOR_MODE 0x27
|
||||
#define CURSOR_MODE_DISABLE 0x00
|
||||
#define CURSOR_MODE_128_32B_AX 0x02
|
||||
#define CURSOR_MODE_256_32B_AX 0x03
|
||||
#define CURSOR_MODE_64_32B_AX 0x07
|
||||
#define CURSOR_MODE_128_ARGB_AX ((1 << 5) | CURSOR_MODE_128_32B_AX)
|
||||
#define CURSOR_MODE_256_ARGB_AX ((1 << 5) | CURSOR_MODE_256_32B_AX)
|
||||
#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
|
||||
#define MCURSOR_PIPE_SELECT (1 << 28)
|
||||
#define MCURSOR_PIPE_A 0x00
|
||||
|
|
|
@ -269,7 +269,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
|
|||
freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
|
||||
ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff);
|
||||
} else {
|
||||
ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
ret = dev_priv->rps.cur_freq * GT_FREQUENCY_MULTIPLIER;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
|
@ -284,7 +284,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay));
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
|
||||
}
|
||||
|
||||
static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
|
@ -298,9 +298,9 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
|
|||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
if (IS_VALLEYVIEW(dev_priv->dev))
|
||||
ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
|
||||
ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
|
||||
else
|
||||
ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
ret = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
|
||||
|
@ -313,7 +313,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
|
|||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val, rp_state_cap, hw_max, hw_min, non_oc_max;
|
||||
u32 val;
|
||||
ssize_t ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &val);
|
||||
|
@ -324,44 +324,35 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
|
|||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (IS_VALLEYVIEW(dev_priv->dev)) {
|
||||
if (IS_VALLEYVIEW(dev_priv->dev))
|
||||
val = vlv_freq_opcode(dev_priv, val);
|
||||
|
||||
hw_max = valleyview_rps_max_freq(dev_priv);
|
||||
hw_min = valleyview_rps_min_freq(dev_priv);
|
||||
non_oc_max = hw_max;
|
||||
} else {
|
||||
else
|
||||
val /= GT_FREQUENCY_MULTIPLIER;
|
||||
|
||||
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
hw_max = dev_priv->rps.hw_max;
|
||||
non_oc_max = (rp_state_cap & 0xff);
|
||||
hw_min = ((rp_state_cap & 0xff0000) >> 16);
|
||||
}
|
||||
|
||||
if (val < hw_min || val > hw_max ||
|
||||
val < dev_priv->rps.min_delay) {
|
||||
if (val < dev_priv->rps.min_freq ||
|
||||
val > dev_priv->rps.max_freq ||
|
||||
val < dev_priv->rps.min_freq_softlimit) {
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (val > non_oc_max)
|
||||
if (val > dev_priv->rps.rp0_freq)
|
||||
DRM_DEBUG("User requested overclocking to %d\n",
|
||||
val * GT_FREQUENCY_MULTIPLIER);
|
||||
|
||||
dev_priv->rps.max_delay = val;
|
||||
dev_priv->rps.max_freq_softlimit = val;
|
||||
|
||||
if (dev_priv->rps.cur_delay > val) {
|
||||
if (dev_priv->rps.cur_freq > val) {
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev, val);
|
||||
else
|
||||
gen6_set_rps(dev, val);
|
||||
} else if (!IS_VALLEYVIEW(dev)) {
|
||||
/* We still need gen6_set_rps to process the new max_delay and
|
||||
* update the interrupt limits even though frequency request is
|
||||
* unchanged. */
|
||||
gen6_set_rps(dev, dev_priv->rps.cur_freq);
|
||||
}
|
||||
else if (!IS_VALLEYVIEW(dev))
|
||||
/* We still need gen6_set_rps to process the new max_delay
|
||||
and update the interrupt limits even though frequency
|
||||
request is unchanged. */
|
||||
gen6_set_rps(dev, dev_priv->rps.cur_delay);
|
||||
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
|
@ -379,9 +370,9 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
|
|||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
if (IS_VALLEYVIEW(dev_priv->dev))
|
||||
ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
|
||||
ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
|
||||
else
|
||||
ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
|
||||
ret = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
|
||||
|
@ -394,7 +385,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
|
|||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val, rp_state_cap, hw_max, hw_min;
|
||||
u32 val;
|
||||
ssize_t ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &val);
|
||||
|
@ -405,37 +396,31 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
|
|||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
val = vlv_freq_opcode(dev_priv, val);
|
||||
|
||||
hw_max = valleyview_rps_max_freq(dev_priv);
|
||||
hw_min = valleyview_rps_min_freq(dev_priv);
|
||||
} else {
|
||||
else
|
||||
val /= GT_FREQUENCY_MULTIPLIER;
|
||||
|
||||
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
hw_max = dev_priv->rps.hw_max;
|
||||
hw_min = ((rp_state_cap & 0xff0000) >> 16);
|
||||
}
|
||||
|
||||
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
|
||||
if (val < dev_priv->rps.min_freq ||
|
||||
val > dev_priv->rps.max_freq ||
|
||||
val > dev_priv->rps.max_freq_softlimit) {
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->rps.min_delay = val;
|
||||
dev_priv->rps.min_freq_softlimit = val;
|
||||
|
||||
if (dev_priv->rps.cur_delay < val) {
|
||||
if (dev_priv->rps.cur_freq < val) {
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev, val);
|
||||
else
|
||||
gen6_set_rps(dev, val);
|
||||
} else if (!IS_VALLEYVIEW(dev)) {
|
||||
/* We still need gen6_set_rps to process the new min_delay and
|
||||
* update the interrupt limits even though frequency request is
|
||||
* unchanged. */
|
||||
gen6_set_rps(dev, dev_priv->rps.cur_freq);
|
||||
}
|
||||
else if (!IS_VALLEYVIEW(dev))
|
||||
/* We still need gen6_set_rps to process the new min_delay
|
||||
and update the interrupt limits even though frequency
|
||||
request is unchanged. */
|
||||
gen6_set_rps(dev, dev_priv->rps.cur_delay);
|
||||
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
|
|
|
@ -238,14 +238,16 @@ TRACE_EVENT(i915_gem_evict_vm,
|
|||
TP_ARGS(vm),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, dev)
|
||||
__field(struct i915_address_space *, vm)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = vm->dev->primary->index;
|
||||
__entry->vm = vm;
|
||||
),
|
||||
|
||||
TP_printk("dev=%d, vm=%p", __entry->vm->dev->primary->index, __entry->vm)
|
||||
TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm)
|
||||
);
|
||||
|
||||
TRACE_EVENT(i915_gem_ring_sync_to,
|
||||
|
|
|
@ -839,7 +839,7 @@ void intel_crt_init(struct drm_device *dev)
|
|||
intel_connector_attach_encoder(intel_connector, &crt->base);
|
||||
|
||||
crt->base.type = INTEL_OUTPUT_ANALOG;
|
||||
crt->base.cloneable = true;
|
||||
crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI);
|
||||
if (IS_I830(dev))
|
||||
crt->base.crtc_mask = (1 << 0);
|
||||
else
|
||||
|
|
|
@ -1340,6 +1340,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
|||
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
||||
intel_edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_panel_off(intel_dp);
|
||||
}
|
||||
|
||||
|
@ -1717,7 +1718,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
|
|||
|
||||
intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
intel_encoder->hot_plug = intel_ddi_hot_plug;
|
||||
|
||||
if (init_dp)
|
||||
|
|
|
@ -741,7 +741,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
|
|||
* We can ditch the adjusted_mode.crtc_clock check as soon
|
||||
* as Haswell has gained clock readout/fastboot support.
|
||||
*
|
||||
* We can ditch the crtc->fb check as soon as we can
|
||||
* We can ditch the crtc->primary->fb check as soon as we can
|
||||
* properly reconstruct framebuffers.
|
||||
*/
|
||||
return intel_crtc->active && crtc->primary->fb &&
|
||||
|
@ -1166,7 +1166,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
|
|||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
reg = DSPCNTR(pipe);
|
||||
val = I915_READ(reg);
|
||||
WARN((val & DISPLAY_PLANE_ENABLE),
|
||||
WARN(val & DISPLAY_PLANE_ENABLE,
|
||||
"plane %c assertion failure, should be disabled but not\n",
|
||||
plane_name(pipe));
|
||||
return;
|
||||
|
@ -1195,20 +1195,20 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
|
|||
for_each_sprite(pipe, sprite) {
|
||||
reg = SPCNTR(pipe, sprite);
|
||||
val = I915_READ(reg);
|
||||
WARN((val & SP_ENABLE),
|
||||
WARN(val & SP_ENABLE,
|
||||
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
|
||||
sprite_name(pipe, sprite), pipe_name(pipe));
|
||||
}
|
||||
} else if (INTEL_INFO(dev)->gen >= 7) {
|
||||
reg = SPRCTL(pipe);
|
||||
val = I915_READ(reg);
|
||||
WARN((val & SPRITE_ENABLE),
|
||||
WARN(val & SPRITE_ENABLE,
|
||||
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
|
||||
plane_name(pipe), pipe_name(pipe));
|
||||
} else if (INTEL_INFO(dev)->gen >= 5) {
|
||||
reg = DVSCNTR(pipe);
|
||||
val = I915_READ(reg);
|
||||
WARN((val & DVS_ENABLE),
|
||||
WARN(val & DVS_ENABLE,
|
||||
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
|
||||
plane_name(pipe), pipe_name(pipe));
|
||||
}
|
||||
|
@ -1872,15 +1872,15 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
|
||||
/**
|
||||
* intel_enable_primary_plane - enable the primary plane on a given pipe
|
||||
* intel_enable_primary_hw_plane - enable the primary plane on a given pipe
|
||||
* @dev_priv: i915 private structure
|
||||
* @plane: plane to enable
|
||||
* @pipe: pipe being fed
|
||||
*
|
||||
* Enable @plane on @pipe, making sure that @pipe is running first.
|
||||
*/
|
||||
static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane, enum pipe pipe)
|
||||
static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane, enum pipe pipe)
|
||||
{
|
||||
struct intel_crtc *intel_crtc =
|
||||
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
|
||||
|
@ -1905,15 +1905,15 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
|
||||
/**
|
||||
* intel_disable_primary_plane - disable the primary plane
|
||||
* intel_disable_primary_hw_plane - disable the primary hardware plane
|
||||
* @dev_priv: i915 private structure
|
||||
* @plane: plane to disable
|
||||
* @pipe: pipe consuming the data
|
||||
*
|
||||
* Disable @plane; should be an independent operation.
|
||||
*/
|
||||
static void intel_disable_primary_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane, enum pipe pipe)
|
||||
static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
|
||||
enum plane plane, enum pipe pipe)
|
||||
{
|
||||
struct intel_crtc *intel_crtc =
|
||||
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
|
||||
|
@ -2047,8 +2047,114 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
|
|||
}
|
||||
}
|
||||
|
||||
static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
||||
int x, int y)
|
||||
int intel_format_to_fourcc(int format)
|
||||
{
|
||||
switch (format) {
|
||||
case DISPPLANE_8BPP:
|
||||
return DRM_FORMAT_C8;
|
||||
case DISPPLANE_BGRX555:
|
||||
return DRM_FORMAT_XRGB1555;
|
||||
case DISPPLANE_BGRX565:
|
||||
return DRM_FORMAT_RGB565;
|
||||
default:
|
||||
case DISPPLANE_BGRX888:
|
||||
return DRM_FORMAT_XRGB8888;
|
||||
case DISPPLANE_RGBX888:
|
||||
return DRM_FORMAT_XBGR8888;
|
||||
case DISPPLANE_BGRX101010:
|
||||
return DRM_FORMAT_XRGB2101010;
|
||||
case DISPPLANE_RGBX101010:
|
||||
return DRM_FORMAT_XBGR2101010;
|
||||
}
|
||||
}
|
||||
|
||||
static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
|
||||
struct intel_plane_config *plane_config)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct drm_i915_gem_object *obj = NULL;
|
||||
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
|
||||
u32 base = plane_config->base;
|
||||
|
||||
if (plane_config->size == 0)
|
||||
return false;
|
||||
|
||||
obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base,
|
||||
plane_config->size);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (plane_config->tiled) {
|
||||
obj->tiling_mode = I915_TILING_X;
|
||||
obj->stride = crtc->base.primary->fb->pitches[0];
|
||||
}
|
||||
|
||||
mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
|
||||
mode_cmd.width = crtc->base.primary->fb->width;
|
||||
mode_cmd.height = crtc->base.primary->fb->height;
|
||||
mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.primary->fb),
|
||||
&mode_cmd, obj)) {
|
||||
DRM_DEBUG_KMS("intel fb init failed\n");
|
||||
goto out_unref_obj;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG_KMS("plane fb obj %p\n", obj);
|
||||
return true;
|
||||
|
||||
out_unref_obj:
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
|
||||
struct intel_plane_config *plane_config)
|
||||
{
|
||||
struct drm_device *dev = intel_crtc->base.dev;
|
||||
struct drm_crtc *c;
|
||||
struct intel_crtc *i;
|
||||
struct intel_framebuffer *fb;
|
||||
|
||||
if (!intel_crtc->base.primary->fb)
|
||||
return;
|
||||
|
||||
if (intel_alloc_plane_obj(intel_crtc, plane_config))
|
||||
return;
|
||||
|
||||
kfree(intel_crtc->base.primary->fb);
|
||||
intel_crtc->base.primary->fb = NULL;
|
||||
|
||||
/*
|
||||
* Failed to alloc the obj, check to see if we should share
|
||||
* an fb with another CRTC instead
|
||||
*/
|
||||
list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
|
||||
i = to_intel_crtc(c);
|
||||
|
||||
if (c == &intel_crtc->base)
|
||||
continue;
|
||||
|
||||
if (!i->active || !c->primary->fb)
|
||||
continue;
|
||||
|
||||
fb = to_intel_framebuffer(c->primary->fb);
|
||||
if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
|
||||
drm_framebuffer_reference(c->primary->fb);
|
||||
intel_crtc->base.primary->fb = c->primary->fb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int i9xx_update_primary_plane(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
int x, int y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -2147,8 +2253,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ironlake_update_plane(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb, int x, int y)
|
||||
static int ironlake_update_primary_plane(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
int x, int y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -2252,7 +2359,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||
dev_priv->display.disable_fbc(dev);
|
||||
intel_increase_pllclock(crtc);
|
||||
|
||||
return dev_priv->display.update_plane(crtc, fb, x, y);
|
||||
return dev_priv->display.update_primary_plane(crtc, fb, x, y);
|
||||
}
|
||||
|
||||
void intel_display_handle_reset(struct drm_device *dev)
|
||||
|
@ -2289,11 +2396,13 @@ void intel_display_handle_reset(struct drm_device *dev)
|
|||
/*
|
||||
* FIXME: Once we have proper support for primary planes (and
|
||||
* disabling them without disabling the entire crtc) allow again
|
||||
* a NULL crtc->fb.
|
||||
* a NULL crtc->primary->fb.
|
||||
*/
|
||||
if (intel_crtc->active && crtc->primary->fb)
|
||||
dev_priv->display.update_plane(crtc, crtc->primary->fb,
|
||||
crtc->x, crtc->y);
|
||||
dev_priv->display.update_primary_plane(crtc,
|
||||
crtc->primary->fb,
|
||||
crtc->x,
|
||||
crtc->y);
|
||||
mutex_unlock(&crtc->mutex);
|
||||
}
|
||||
}
|
||||
|
@ -2372,8 +2481,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
ret = intel_pin_and_fence_fb_obj(dev,
|
||||
to_intel_framebuffer(fb)->obj,
|
||||
NULL);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (ret != 0) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_ERROR("pin & fence failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -2409,8 +2518,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
|
||||
}
|
||||
|
||||
ret = dev_priv->display.update_plane(crtc, fb, x, y);
|
||||
ret = dev_priv->display.update_primary_plane(crtc, fb, x, y);
|
||||
if (ret) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_ERROR("failed to update base address\n");
|
||||
|
@ -2425,9 +2535,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
if (old_fb) {
|
||||
if (intel_crtc->active && old_fb != fb)
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
intel_update_fbc(dev);
|
||||
intel_edp_psr_update(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
@ -3592,7 +3705,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
|
|||
|
||||
intel_update_watermarks(crtc);
|
||||
intel_enable_pipe(intel_crtc);
|
||||
intel_enable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_enable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
intel_enable_planes(crtc);
|
||||
intel_crtc_update_cursor(crtc, true);
|
||||
|
||||
|
@ -3634,7 +3747,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
|
|||
int pipe = intel_crtc->pipe;
|
||||
int plane = intel_crtc->plane;
|
||||
|
||||
intel_enable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_enable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
intel_enable_planes(crtc);
|
||||
intel_crtc_update_cursor(crtc, true);
|
||||
|
||||
|
@ -3664,7 +3777,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
|
|||
|
||||
intel_crtc_update_cursor(crtc, false);
|
||||
intel_disable_planes(crtc);
|
||||
intel_disable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_disable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3792,7 +3905,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
|
|||
|
||||
intel_crtc_update_cursor(crtc, false);
|
||||
intel_disable_planes(crtc);
|
||||
intel_disable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_disable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
|
||||
if (intel_crtc->config.has_pch_encoder)
|
||||
intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
|
||||
|
@ -4275,7 +4388,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
|
|||
intel_update_watermarks(crtc);
|
||||
intel_enable_pipe(intel_crtc);
|
||||
intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
|
||||
intel_enable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_enable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
intel_enable_planes(crtc);
|
||||
intel_crtc_update_cursor(crtc, true);
|
||||
|
||||
|
@ -4314,7 +4427,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
|
|||
intel_update_watermarks(crtc);
|
||||
intel_enable_pipe(intel_crtc);
|
||||
intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
|
||||
intel_enable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_enable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
intel_enable_planes(crtc);
|
||||
/* The fixup needs to happen before cursor is enabled */
|
||||
if (IS_G4X(dev))
|
||||
|
@ -4370,7 +4483,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
|
|||
intel_crtc_dpms_overlay(intel_crtc, false);
|
||||
intel_crtc_update_cursor(crtc, false);
|
||||
intel_disable_planes(crtc);
|
||||
intel_disable_primary_plane(dev_priv, plane, pipe);
|
||||
intel_disable_primary_hw_plane(dev_priv, plane, pipe);
|
||||
|
||||
intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
|
||||
intel_disable_pipe(dev_priv, pipe);
|
||||
|
@ -5611,6 +5724,67 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc,
|
|||
pipe_config->port_clock = clock.dot / 5;
|
||||
}
|
||||
|
||||
static void i9xx_get_plane_config(struct intel_crtc *crtc,
|
||||
struct intel_plane_config *plane_config)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val, base, offset;
|
||||
int pipe = crtc->pipe, plane = crtc->plane;
|
||||
int fourcc, pixel_format;
|
||||
int aligned_height;
|
||||
|
||||
crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
|
||||
if (!crtc->base.primary->fb) {
|
||||
DRM_DEBUG_KMS("failed to alloc fb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
val = I915_READ(DSPCNTR(plane));
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
if (val & DISPPLANE_TILED)
|
||||
plane_config->tiled = true;
|
||||
|
||||
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
|
||||
fourcc = intel_format_to_fourcc(pixel_format);
|
||||
crtc->base.primary->fb->pixel_format = fourcc;
|
||||
crtc->base.primary->fb->bits_per_pixel =
|
||||
drm_format_plane_cpp(fourcc, 0) * 8;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4) {
|
||||
if (plane_config->tiled)
|
||||
offset = I915_READ(DSPTILEOFF(plane));
|
||||
else
|
||||
offset = I915_READ(DSPLINOFF(plane));
|
||||
base = I915_READ(DSPSURF(plane)) & 0xfffff000;
|
||||
} else {
|
||||
base = I915_READ(DSPADDR(plane));
|
||||
}
|
||||
plane_config->base = base;
|
||||
|
||||
val = I915_READ(PIPESRC(pipe));
|
||||
crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
|
||||
crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
|
||||
|
||||
val = I915_READ(DSPSTRIDE(pipe));
|
||||
crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
|
||||
|
||||
aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
|
||||
plane_config->tiled);
|
||||
|
||||
plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
|
||||
aligned_height, PAGE_SIZE);
|
||||
|
||||
DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
|
||||
pipe, plane, crtc->base.primary->fb->width,
|
||||
crtc->base.primary->fb->height,
|
||||
crtc->base.primary->fb->bits_per_pixel, base,
|
||||
crtc->base.primary->fb->pitches[0],
|
||||
plane_config->size);
|
||||
|
||||
}
|
||||
|
||||
static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
|
@ -6558,6 +6732,66 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
|
|||
}
|
||||
}
|
||||
|
||||
static void ironlake_get_plane_config(struct intel_crtc *crtc,
|
||||
struct intel_plane_config *plane_config)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 val, base, offset;
|
||||
int pipe = crtc->pipe, plane = crtc->plane;
|
||||
int fourcc, pixel_format;
|
||||
int aligned_height;
|
||||
|
||||
crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
|
||||
if (!crtc->base.primary->fb) {
|
||||
DRM_DEBUG_KMS("failed to alloc fb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
val = I915_READ(DSPCNTR(plane));
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 4)
|
||||
if (val & DISPPLANE_TILED)
|
||||
plane_config->tiled = true;
|
||||
|
||||
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
|
||||
fourcc = intel_format_to_fourcc(pixel_format);
|
||||
crtc->base.primary->fb->pixel_format = fourcc;
|
||||
crtc->base.primary->fb->bits_per_pixel =
|
||||
drm_format_plane_cpp(fourcc, 0) * 8;
|
||||
|
||||
base = I915_READ(DSPSURF(plane)) & 0xfffff000;
|
||||
if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
|
||||
offset = I915_READ(DSPOFFSET(plane));
|
||||
} else {
|
||||
if (plane_config->tiled)
|
||||
offset = I915_READ(DSPTILEOFF(plane));
|
||||
else
|
||||
offset = I915_READ(DSPLINOFF(plane));
|
||||
}
|
||||
plane_config->base = base;
|
||||
|
||||
val = I915_READ(PIPESRC(pipe));
|
||||
crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
|
||||
crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
|
||||
|
||||
val = I915_READ(DSPSTRIDE(pipe));
|
||||
crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
|
||||
|
||||
aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
|
||||
plane_config->tiled);
|
||||
|
||||
plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
|
||||
aligned_height, PAGE_SIZE);
|
||||
|
||||
DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
|
||||
pipe, plane, crtc->base.primary->fb->width,
|
||||
crtc->base.primary->fb->height,
|
||||
crtc->base.primary->fb->bits_per_pixel, base,
|
||||
crtc->base.primary->fb->pitches[0],
|
||||
plane_config->size);
|
||||
}
|
||||
|
||||
static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
|
@ -6732,6 +6966,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
|
|||
static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
uint32_t val;
|
||||
unsigned long irqflags;
|
||||
|
||||
val = I915_READ(LCPLL_CTL);
|
||||
|
||||
|
@ -6739,9 +6974,22 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
|
|||
LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
|
||||
return;
|
||||
|
||||
/* Make sure we're not on PC8 state before disabling PC8, otherwise
|
||||
* we'll hang the machine! */
|
||||
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
|
||||
/*
|
||||
* Make sure we're not on PC8 state before disabling PC8, otherwise
|
||||
* we'll hang the machine. To prevent PC8 state, just enable force_wake.
|
||||
*
|
||||
* The other problem is that hsw_restore_lcpll() is called as part of
|
||||
* the runtime PM resume sequence, so we can't just call
|
||||
* gen6_gt_force_wake_get() because that function calls
|
||||
* intel_runtime_pm_get(), and we can't change the runtime PM refcount
|
||||
* while we are on the resume sequence. So to solve this problem we have
|
||||
* to call special forcewake code that doesn't touch runtime PM and
|
||||
* doesn't enable the forcewake delayed work.
|
||||
*/
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
if (dev_priv->uncore.forcewake_count++ == 0)
|
||||
dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
|
||||
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
||||
|
||||
if (val & LCPLL_POWER_DOWN_ALLOW) {
|
||||
val &= ~LCPLL_POWER_DOWN_ALLOW;
|
||||
|
@ -6775,26 +7023,45 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
|
|||
DRM_ERROR("Switching back to LCPLL failed\n");
|
||||
}
|
||||
|
||||
gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
/* See the big comment above. */
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
if (--dev_priv->uncore.forcewake_count == 0)
|
||||
dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
||||
}
|
||||
|
||||
void hsw_enable_pc8_work(struct work_struct *__work)
|
||||
/*
|
||||
* Package states C8 and deeper are really deep PC states that can only be
|
||||
* reached when all the devices on the system allow it, so even if the graphics
|
||||
* device allows PC8+, it doesn't mean the system will actually get to these
|
||||
* states. Our driver only allows PC8+ when going into runtime PM.
|
||||
*
|
||||
* The requirements for PC8+ are that all the outputs are disabled, the power
|
||||
* well is disabled and most interrupts are disabled, and these are also
|
||||
* requirements for runtime PM. When these conditions are met, we manually do
|
||||
* the other conditions: disable the interrupts, clocks and switch LCPLL refclk
|
||||
* to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
|
||||
* hang the machine.
|
||||
*
|
||||
* When we really reach PC8 or deeper states (not just when we allow it) we lose
|
||||
* the state of some registers, so when we come back from PC8+ we need to
|
||||
* restore this state. We don't get into PC8+ if we're not in RC6, so we don't
|
||||
* need to take care of the registers kept by RC6. Notice that this happens even
|
||||
* if we don't put the device in PCI D3 state (which is what currently happens
|
||||
* because of the runtime PM support).
|
||||
*
|
||||
* For more, read "Display Sequences for Package C8" on the hardware
|
||||
* documentation.
|
||||
*/
|
||||
void hsw_enable_pc8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv =
|
||||
container_of(to_delayed_work(__work), struct drm_i915_private,
|
||||
pc8.enable_work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
uint32_t val;
|
||||
|
||||
WARN_ON(!HAS_PC8(dev));
|
||||
|
||||
if (dev_priv->pc8.enabled)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("Enabling package C8+\n");
|
||||
|
||||
dev_priv->pc8.enabled = true;
|
||||
|
||||
if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
|
||||
val = I915_READ(SOUTH_DSPCLK_GATE_D);
|
||||
val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
|
||||
|
@ -6802,51 +7069,21 @@ void hsw_enable_pc8_work(struct work_struct *__work)
|
|||
}
|
||||
|
||||
lpt_disable_clkout_dp(dev);
|
||||
hsw_pc8_disable_interrupts(dev);
|
||||
hsw_runtime_pm_disable_interrupts(dev);
|
||||
hsw_disable_lcpll(dev_priv, true, true);
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
|
||||
WARN(dev_priv->pc8.disable_count < 1,
|
||||
"pc8.disable_count: %d\n", dev_priv->pc8.disable_count);
|
||||
|
||||
dev_priv->pc8.disable_count--;
|
||||
if (dev_priv->pc8.disable_count != 0)
|
||||
return;
|
||||
|
||||
schedule_delayed_work(&dev_priv->pc8.enable_work,
|
||||
msecs_to_jiffies(i915.pc8_timeout));
|
||||
}
|
||||
|
||||
static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
|
||||
void hsw_disable_pc8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
uint32_t val;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
|
||||
WARN(dev_priv->pc8.disable_count < 0,
|
||||
"pc8.disable_count: %d\n", dev_priv->pc8.disable_count);
|
||||
|
||||
dev_priv->pc8.disable_count++;
|
||||
if (dev_priv->pc8.disable_count != 1)
|
||||
return;
|
||||
|
||||
WARN_ON(!HAS_PC8(dev));
|
||||
|
||||
cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
|
||||
if (!dev_priv->pc8.enabled)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("Disabling package C8+\n");
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
hsw_restore_lcpll(dev_priv);
|
||||
hsw_pc8_restore_interrupts(dev);
|
||||
hsw_runtime_pm_restore_interrupts(dev);
|
||||
lpt_init_pch_refclk(dev);
|
||||
|
||||
if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
|
||||
|
@ -6860,89 +7097,11 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
|
|||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
gen6_update_ring_freq(dev);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
dev_priv->pc8.enabled = false;
|
||||
}
|
||||
|
||||
void hsw_enable_package_c8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (!HAS_PC8(dev_priv->dev))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->pc8.lock);
|
||||
__hsw_enable_package_c8(dev_priv);
|
||||
mutex_unlock(&dev_priv->pc8.lock);
|
||||
}
|
||||
|
||||
void hsw_disable_package_c8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (!HAS_PC8(dev_priv->dev))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->pc8.lock);
|
||||
__hsw_disable_package_c8(dev_priv);
|
||||
mutex_unlock(&dev_priv->pc8.lock);
|
||||
}
|
||||
|
||||
static bool hsw_can_enable_package_c8(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct intel_crtc *crtc;
|
||||
uint32_t val;
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
|
||||
if (crtc->base.enabled)
|
||||
return false;
|
||||
|
||||
/* This case is still possible since we have the i915.disable_power_well
|
||||
* parameter and also the KVMr or something else might be requesting the
|
||||
* power well. */
|
||||
val = I915_READ(HSW_PWR_WELL_DRIVER);
|
||||
if (val != 0) {
|
||||
DRM_DEBUG_KMS("Not enabling PC8: power well on\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Since we're called from modeset_global_resources there's no way to
|
||||
* symmetrically increase and decrease the refcount, so we use
|
||||
* dev_priv->pc8.requirements_met to track whether we already have the refcount
|
||||
* or not.
|
||||
*/
|
||||
static void hsw_update_package_c8(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
bool allow;
|
||||
|
||||
if (!HAS_PC8(dev_priv->dev))
|
||||
return;
|
||||
|
||||
if (!i915.enable_pc8)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->pc8.lock);
|
||||
|
||||
allow = hsw_can_enable_package_c8(dev_priv);
|
||||
|
||||
if (allow == dev_priv->pc8.requirements_met)
|
||||
goto done;
|
||||
|
||||
dev_priv->pc8.requirements_met = allow;
|
||||
|
||||
if (allow)
|
||||
__hsw_enable_package_c8(dev_priv);
|
||||
else
|
||||
__hsw_disable_package_c8(dev_priv);
|
||||
|
||||
done:
|
||||
mutex_unlock(&dev_priv->pc8.lock);
|
||||
}
|
||||
|
||||
static void haswell_modeset_global_resources(struct drm_device *dev)
|
||||
{
|
||||
modeset_update_crtc_power_domains(dev);
|
||||
hsw_update_package_c8(dev);
|
||||
}
|
||||
|
||||
static int haswell_crtc_mode_set(struct drm_crtc *crtc,
|
||||
|
@ -7446,10 +7605,26 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
|
|||
bool visible = base != 0;
|
||||
|
||||
if (intel_crtc->cursor_visible != visible) {
|
||||
int16_t width = intel_crtc->cursor_width;
|
||||
uint32_t cntl = I915_READ(CURCNTR(pipe));
|
||||
if (base) {
|
||||
cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
|
||||
cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
|
||||
cntl |= MCURSOR_GAMMA_ENABLE;
|
||||
|
||||
switch (width) {
|
||||
case 64:
|
||||
cntl |= CURSOR_MODE_64_ARGB_AX;
|
||||
break;
|
||||
case 128:
|
||||
cntl |= CURSOR_MODE_128_ARGB_AX;
|
||||
break;
|
||||
case 256:
|
||||
cntl |= CURSOR_MODE_256_ARGB_AX;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
cntl |= pipe << 28; /* Connect to correct pipe */
|
||||
} else {
|
||||
cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
|
||||
|
@ -7474,10 +7649,25 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
|
|||
bool visible = base != 0;
|
||||
|
||||
if (intel_crtc->cursor_visible != visible) {
|
||||
int16_t width = intel_crtc->cursor_width;
|
||||
uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
|
||||
if (base) {
|
||||
cntl &= ~CURSOR_MODE;
|
||||
cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
|
||||
cntl |= MCURSOR_GAMMA_ENABLE;
|
||||
switch (width) {
|
||||
case 64:
|
||||
cntl |= CURSOR_MODE_64_ARGB_AX;
|
||||
break;
|
||||
case 128:
|
||||
cntl |= CURSOR_MODE_128_ARGB_AX;
|
||||
break;
|
||||
case 256:
|
||||
cntl |= CURSOR_MODE_256_ARGB_AX;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
|
||||
cntl |= CURSOR_MODE_DISABLE;
|
||||
|
@ -7573,9 +7763,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
goto finish;
|
||||
}
|
||||
|
||||
/* Currently we only support 64x64 cursors */
|
||||
if (width != 64 || height != 64) {
|
||||
DRM_ERROR("we currently only support 64x64 cursors\n");
|
||||
/* Check for which cursor types we support */
|
||||
if (!((width == 64 && height == 64) ||
|
||||
(width == 128 && height == 128 && !IS_GEN2(dev)) ||
|
||||
(width == 256 && height == 256 && !IS_GEN2(dev)))) {
|
||||
DRM_DEBUG("Cursor dimension not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -8230,7 +8422,7 @@ void intel_mark_busy(struct drm_device *dev)
|
|||
if (dev_priv->mm.busy)
|
||||
return;
|
||||
|
||||
hsw_disable_package_c8(dev_priv);
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
i915_update_gfx_val(dev_priv);
|
||||
dev_priv->mm.busy = true;
|
||||
}
|
||||
|
@ -8259,7 +8451,7 @@ void intel_mark_idle(struct drm_device *dev)
|
|||
gen6_rps_idle(dev->dev_private);
|
||||
|
||||
out:
|
||||
hsw_enable_package_c8(dev_priv);
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
|
||||
|
@ -9015,23 +9207,47 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
|
|||
DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
|
||||
}
|
||||
|
||||
static bool check_encoder_cloning(struct drm_crtc *crtc)
|
||||
static bool encoders_cloneable(const struct intel_encoder *a,
|
||||
const struct intel_encoder *b)
|
||||
{
|
||||
int num_encoders = 0;
|
||||
bool uncloneable_encoders = false;
|
||||
struct intel_encoder *encoder;
|
||||
/* masks could be asymmetric, so check both ways */
|
||||
return a == b || (a->cloneable & (1 << b->type) &&
|
||||
b->cloneable & (1 << a->type));
|
||||
}
|
||||
|
||||
list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
|
||||
base.head) {
|
||||
if (&encoder->new_crtc->base != crtc)
|
||||
static bool check_single_encoder_cloning(struct intel_crtc *crtc,
|
||||
struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct intel_encoder *source_encoder;
|
||||
|
||||
list_for_each_entry(source_encoder,
|
||||
&dev->mode_config.encoder_list, base.head) {
|
||||
if (source_encoder->new_crtc != crtc)
|
||||
continue;
|
||||
|
||||
num_encoders++;
|
||||
if (!encoder->cloneable)
|
||||
uncloneable_encoders = true;
|
||||
if (!encoders_cloneable(encoder, source_encoder))
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(num_encoders > 1 && uncloneable_encoders);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_encoder_cloning(struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct intel_encoder *encoder;
|
||||
|
||||
list_for_each_entry(encoder,
|
||||
&dev->mode_config.encoder_list, base.head) {
|
||||
if (encoder->new_crtc != crtc)
|
||||
continue;
|
||||
|
||||
if (!check_single_encoder_cloning(crtc, encoder))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct intel_crtc_config *
|
||||
|
@ -9045,7 +9261,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
|
|||
int plane_bpp, ret = -EINVAL;
|
||||
bool retry = true;
|
||||
|
||||
if (!check_encoder_cloning(crtc)) {
|
||||
if (!check_encoder_cloning(to_intel_crtc(crtc))) {
|
||||
DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -10337,6 +10553,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
|
|||
|
||||
drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
|
||||
|
||||
if (IS_GEN2(dev)) {
|
||||
intel_crtc->max_cursor_width = GEN2_CURSOR_WIDTH;
|
||||
intel_crtc->max_cursor_height = GEN2_CURSOR_HEIGHT;
|
||||
} else {
|
||||
intel_crtc->max_cursor_width = CURSOR_WIDTH;
|
||||
intel_crtc->max_cursor_height = CURSOR_HEIGHT;
|
||||
}
|
||||
dev->mode_config.cursor_width = intel_crtc->max_cursor_width;
|
||||
dev->mode_config.cursor_height = intel_crtc->max_cursor_height;
|
||||
|
||||
drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
|
||||
for (i = 0; i < 256; i++) {
|
||||
intel_crtc->lut_r[i] = i;
|
||||
|
@ -10408,12 +10634,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder)
|
|||
|
||||
list_for_each_entry(source_encoder,
|
||||
&dev->mode_config.encoder_list, base.head) {
|
||||
|
||||
if (encoder == source_encoder)
|
||||
index_mask |= (1 << entry);
|
||||
|
||||
/* Intel hw has only one MUX where enocoders could be cloned. */
|
||||
if (encoder->cloneable && source_encoder->cloneable)
|
||||
if (encoders_cloneable(encoder, source_encoder))
|
||||
index_mask |= (1 << entry);
|
||||
|
||||
entry++;
|
||||
|
@ -10770,32 +10991,40 @@ static void intel_init_display(struct drm_device *dev)
|
|||
|
||||
if (HAS_DDI(dev)) {
|
||||
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
|
||||
dev_priv->display.get_plane_config = ironlake_get_plane_config;
|
||||
dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
|
||||
dev_priv->display.crtc_enable = haswell_crtc_enable;
|
||||
dev_priv->display.crtc_disable = haswell_crtc_disable;
|
||||
dev_priv->display.off = haswell_crtc_off;
|
||||
dev_priv->display.update_plane = ironlake_update_plane;
|
||||
dev_priv->display.update_primary_plane =
|
||||
ironlake_update_primary_plane;
|
||||
} else if (HAS_PCH_SPLIT(dev)) {
|
||||
dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
|
||||
dev_priv->display.get_plane_config = ironlake_get_plane_config;
|
||||
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
|
||||
dev_priv->display.crtc_enable = ironlake_crtc_enable;
|
||||
dev_priv->display.crtc_disable = ironlake_crtc_disable;
|
||||
dev_priv->display.off = ironlake_crtc_off;
|
||||
dev_priv->display.update_plane = ironlake_update_plane;
|
||||
dev_priv->display.update_primary_plane =
|
||||
ironlake_update_primary_plane;
|
||||
} else if (IS_VALLEYVIEW(dev)) {
|
||||
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
||||
dev_priv->display.get_plane_config = i9xx_get_plane_config;
|
||||
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
|
||||
dev_priv->display.crtc_enable = valleyview_crtc_enable;
|
||||
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
||||
dev_priv->display.off = i9xx_crtc_off;
|
||||
dev_priv->display.update_plane = i9xx_update_plane;
|
||||
dev_priv->display.update_primary_plane =
|
||||
i9xx_update_primary_plane;
|
||||
} else {
|
||||
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
|
||||
dev_priv->display.get_plane_config = i9xx_get_plane_config;
|
||||
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
|
||||
dev_priv->display.crtc_enable = i9xx_crtc_enable;
|
||||
dev_priv->display.crtc_disable = i9xx_crtc_disable;
|
||||
dev_priv->display.off = i9xx_crtc_off;
|
||||
dev_priv->display.update_plane = i9xx_update_plane;
|
||||
dev_priv->display.update_primary_plane =
|
||||
i9xx_update_primary_plane;
|
||||
}
|
||||
|
||||
/* Returns the core display clock speed */
|
||||
|
@ -11053,6 +11282,7 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int sprite, ret;
|
||||
enum pipe pipe;
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
|
@ -11115,6 +11345,29 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
mutex_lock(&dev->mode_config.mutex);
|
||||
intel_modeset_setup_hw_state(dev, false);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
|
||||
base.head) {
|
||||
if (!crtc->active)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Note that reserving the BIOS fb up front prevents us
|
||||
* from stuffing other stolen allocations like the ring
|
||||
* on top. This prevents some ugliness at boot time, and
|
||||
* can even allow for smooth boot transitions if the BIOS
|
||||
* fb is large enough for the active pipe configuration.
|
||||
*/
|
||||
if (dev_priv->display.get_plane_config) {
|
||||
dev_priv->display.get_plane_config(crtc,
|
||||
&crtc->plane_config);
|
||||
/*
|
||||
* If the fb is shared between multiple heads, we'll
|
||||
* just get the first one.
|
||||
*/
|
||||
intel_find_plane_obj(crtc, &crtc->plane_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -11484,9 +11737,32 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
|
|||
|
||||
void intel_modeset_gem_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_crtc *c;
|
||||
struct intel_framebuffer *fb;
|
||||
|
||||
intel_modeset_init_hw(dev);
|
||||
|
||||
intel_setup_overlay(dev);
|
||||
|
||||
/*
|
||||
* Make sure any fbs we allocated at startup are properly
|
||||
* pinned & fenced. When we do the allocation it's too early
|
||||
* for this.
|
||||
*/
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
|
||||
if (!c->primary->fb)
|
||||
continue;
|
||||
|
||||
fb = to_intel_framebuffer(c->primary->fb);
|
||||
if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
|
||||
DRM_ERROR("failed to pin boot fb on pipe %d\n",
|
||||
to_intel_crtc(c)->pipe);
|
||||
drm_framebuffer_unreference(c->primary->fb);
|
||||
c->primary->fb = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
void intel_connector_unregister(struct intel_connector *intel_connector)
|
||||
|
|
|
@ -91,7 +91,7 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
|
|||
}
|
||||
|
||||
static void intel_dp_link_down(struct intel_dp *intel_dp);
|
||||
static void edp_panel_vdd_on(struct intel_dp *intel_dp);
|
||||
static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
|
||||
static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
|
||||
|
||||
static int
|
||||
|
@ -460,6 +460,9 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|||
uint32_t status;
|
||||
int try, clock = 0;
|
||||
bool has_aux_irq = HAS_AUX_IRQ(dev);
|
||||
bool vdd;
|
||||
|
||||
vdd = _edp_panel_vdd_on(intel_dp);
|
||||
|
||||
/* dp aux is extremely sensitive to irq latency, hence request the
|
||||
* lowest possible wakeup latency and so prevent the cpu from going into
|
||||
|
@ -565,223 +568,130 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|||
pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
|
||||
intel_aux_display_runtime_put(dev_priv);
|
||||
|
||||
if (vdd)
|
||||
edp_panel_vdd_off(intel_dp, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write data to the aux channel in native mode */
|
||||
static int
|
||||
intel_dp_aux_native_write(struct intel_dp *intel_dp,
|
||||
uint16_t address, uint8_t *send, int send_bytes)
|
||||
#define HEADER_SIZE 4
|
||||
static ssize_t
|
||||
intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
|
||||
uint8_t txbuf[20], rxbuf[20];
|
||||
size_t txsize, rxsize;
|
||||
int ret;
|
||||
uint8_t msg[20];
|
||||
int msg_bytes;
|
||||
uint8_t ack;
|
||||
int retry;
|
||||
|
||||
if (WARN_ON(send_bytes > 16))
|
||||
return -E2BIG;
|
||||
txbuf[0] = msg->request << 4;
|
||||
txbuf[1] = msg->address >> 8;
|
||||
txbuf[2] = msg->address & 0xff;
|
||||
txbuf[3] = msg->size - 1;
|
||||
|
||||
intel_dp_check_edp(intel_dp);
|
||||
msg[0] = DP_AUX_NATIVE_WRITE << 4;
|
||||
msg[1] = address >> 8;
|
||||
msg[2] = address & 0xff;
|
||||
msg[3] = send_bytes - 1;
|
||||
memcpy(&msg[4], send, send_bytes);
|
||||
msg_bytes = send_bytes + 4;
|
||||
for (retry = 0; retry < 7; retry++) {
|
||||
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ack >>= 4;
|
||||
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
|
||||
return send_bytes;
|
||||
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
|
||||
usleep_range(400, 500);
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
switch (msg->request & ~DP_AUX_I2C_MOT) {
|
||||
case DP_AUX_NATIVE_WRITE:
|
||||
case DP_AUX_I2C_WRITE:
|
||||
txsize = HEADER_SIZE + msg->size;
|
||||
rxsize = 1;
|
||||
|
||||
DRM_ERROR("too many retries, giving up\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (WARN_ON(txsize > 20))
|
||||
return -E2BIG;
|
||||
|
||||
/* Write a single byte to the aux channel in native mode */
|
||||
static int
|
||||
intel_dp_aux_native_write_1(struct intel_dp *intel_dp,
|
||||
uint16_t address, uint8_t byte)
|
||||
{
|
||||
return intel_dp_aux_native_write(intel_dp, address, &byte, 1);
|
||||
}
|
||||
memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
|
||||
|
||||
/* read bytes from a native aux channel */
|
||||
static int
|
||||
intel_dp_aux_native_read(struct intel_dp *intel_dp,
|
||||
uint16_t address, uint8_t *recv, int recv_bytes)
|
||||
{
|
||||
uint8_t msg[4];
|
||||
int msg_bytes;
|
||||
uint8_t reply[20];
|
||||
int reply_bytes;
|
||||
uint8_t ack;
|
||||
int ret;
|
||||
int retry;
|
||||
ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
|
||||
if (ret > 0) {
|
||||
msg->reply = rxbuf[0] >> 4;
|
||||
|
||||
if (WARN_ON(recv_bytes > 19))
|
||||
return -E2BIG;
|
||||
|
||||
intel_dp_check_edp(intel_dp);
|
||||
msg[0] = DP_AUX_NATIVE_READ << 4;
|
||||
msg[1] = address >> 8;
|
||||
msg[2] = address & 0xff;
|
||||
msg[3] = recv_bytes - 1;
|
||||
|
||||
msg_bytes = 4;
|
||||
reply_bytes = recv_bytes + 1;
|
||||
|
||||
for (retry = 0; retry < 7; retry++) {
|
||||
ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,
|
||||
reply, reply_bytes);
|
||||
if (ret == 0)
|
||||
return -EPROTO;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ack = reply[0] >> 4;
|
||||
if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) {
|
||||
memcpy(recv, reply + 1, ret - 1);
|
||||
return ret - 1;
|
||||
/* Return payload size. */
|
||||
ret = msg->size;
|
||||
}
|
||||
else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
|
||||
usleep_range(400, 500);
|
||||
else
|
||||
return -EIO;
|
||||
break;
|
||||
|
||||
case DP_AUX_NATIVE_READ:
|
||||
case DP_AUX_I2C_READ:
|
||||
txsize = HEADER_SIZE;
|
||||
rxsize = msg->size + 1;
|
||||
|
||||
if (WARN_ON(rxsize > 20))
|
||||
return -E2BIG;
|
||||
|
||||
ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
|
||||
if (ret > 0) {
|
||||
msg->reply = rxbuf[0] >> 4;
|
||||
/*
|
||||
* Assume happy day, and copy the data. The caller is
|
||||
* expected to check msg->reply before touching it.
|
||||
*
|
||||
* Return payload size.
|
||||
*/
|
||||
ret--;
|
||||
memcpy(msg->buffer, rxbuf + 1, ret);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_ERROR("too many retries, giving up\n");
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
|
||||
uint8_t write_byte, uint8_t *read_byte)
|
||||
static void
|
||||
intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
|
||||
{
|
||||
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
|
||||
struct intel_dp *intel_dp = container_of(adapter,
|
||||
struct intel_dp,
|
||||
adapter);
|
||||
uint16_t address = algo_data->address;
|
||||
uint8_t msg[5];
|
||||
uint8_t reply[2];
|
||||
unsigned retry;
|
||||
int msg_bytes;
|
||||
int reply_bytes;
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
enum port port = intel_dig_port->port;
|
||||
const char *name = NULL;
|
||||
int ret;
|
||||
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
intel_dp_check_edp(intel_dp);
|
||||
/* Set up the command byte */
|
||||
if (mode & MODE_I2C_READ)
|
||||
msg[0] = DP_AUX_I2C_READ << 4;
|
||||
else
|
||||
msg[0] = DP_AUX_I2C_WRITE << 4;
|
||||
|
||||
if (!(mode & MODE_I2C_STOP))
|
||||
msg[0] |= DP_AUX_I2C_MOT << 4;
|
||||
|
||||
msg[1] = address >> 8;
|
||||
msg[2] = address;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_I2C_WRITE:
|
||||
msg[3] = 0;
|
||||
msg[4] = write_byte;
|
||||
msg_bytes = 5;
|
||||
reply_bytes = 1;
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
|
||||
name = "DPDDC-A";
|
||||
break;
|
||||
case MODE_I2C_READ:
|
||||
msg[3] = 0;
|
||||
msg_bytes = 4;
|
||||
reply_bytes = 2;
|
||||
case PORT_B:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
|
||||
name = "DPDDC-B";
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
|
||||
name = "DPDDC-C";
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
|
||||
name = "DPDDC-D";
|
||||
break;
|
||||
default:
|
||||
msg_bytes = 3;
|
||||
reply_bytes = 1;
|
||||
break;
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device is
|
||||
* required to retry at least seven times upon receiving AUX_DEFER
|
||||
* before giving up the AUX transaction.
|
||||
*/
|
||||
for (retry = 0; retry < 7; retry++) {
|
||||
ret = intel_dp_aux_ch(intel_dp,
|
||||
msg, msg_bytes,
|
||||
reply, reply_bytes);
|
||||
if (ret < 0) {
|
||||
DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if (!HAS_DDI(dev))
|
||||
intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
|
||||
|
||||
switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
|
||||
case DP_AUX_NATIVE_REPLY_ACK:
|
||||
/* I2C-over-AUX Reply field is only valid
|
||||
* when paired with AUX ACK.
|
||||
*/
|
||||
break;
|
||||
case DP_AUX_NATIVE_REPLY_NACK:
|
||||
DRM_DEBUG_KMS("aux_ch native nack\n");
|
||||
ret = -EREMOTEIO;
|
||||
goto out;
|
||||
case DP_AUX_NATIVE_REPLY_DEFER:
|
||||
/*
|
||||
* For now, just give more slack to branch devices. We
|
||||
* could check the DPCD for I2C bit rate capabilities,
|
||||
* and if available, adjust the interval. We could also
|
||||
* be more careful with DP-to-Legacy adapters where a
|
||||
* long legacy cable may force very low I2C bit rates.
|
||||
*/
|
||||
if (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DWN_STRM_PORT_PRESENT)
|
||||
usleep_range(500, 600);
|
||||
else
|
||||
usleep_range(300, 400);
|
||||
continue;
|
||||
default:
|
||||
DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
|
||||
reply[0]);
|
||||
ret = -EREMOTEIO;
|
||||
goto out;
|
||||
}
|
||||
intel_dp->aux.name = name;
|
||||
intel_dp->aux.dev = dev->dev;
|
||||
intel_dp->aux.transfer = intel_dp_aux_transfer;
|
||||
|
||||
switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) {
|
||||
case DP_AUX_I2C_REPLY_ACK:
|
||||
if (mode == MODE_I2C_READ) {
|
||||
*read_byte = reply[1];
|
||||
}
|
||||
ret = reply_bytes - 1;
|
||||
goto out;
|
||||
case DP_AUX_I2C_REPLY_NACK:
|
||||
DRM_DEBUG_KMS("aux_i2c nack\n");
|
||||
ret = -EREMOTEIO;
|
||||
goto out;
|
||||
case DP_AUX_I2C_REPLY_DEFER:
|
||||
DRM_DEBUG_KMS("aux_i2c defer\n");
|
||||
udelay(100);
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
|
||||
ret = -EREMOTEIO;
|
||||
goto out;
|
||||
}
|
||||
DRM_DEBUG_KMS("registering %s bus for %s\n", name,
|
||||
connector->base.kdev->kobj.name);
|
||||
|
||||
ret = drm_dp_aux_register_i2c_bus(&intel_dp->aux);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("drm_dp_aux_register_i2c_bus() for %s failed (%d)\n",
|
||||
name, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_ERROR("too many retries, giving up\n");
|
||||
ret = -EREMOTEIO;
|
||||
|
||||
out:
|
||||
edp_panel_vdd_off(intel_dp, false);
|
||||
return ret;
|
||||
ret = sysfs_create_link(&connector->base.kdev->kobj,
|
||||
&intel_dp->aux.ddc.dev.kobj,
|
||||
intel_dp->aux.ddc.dev.kobj.name);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
|
||||
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -790,43 +700,10 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
|
|||
struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
|
||||
|
||||
sysfs_remove_link(&intel_connector->base.kdev->kobj,
|
||||
intel_dp->adapter.dev.kobj.name);
|
||||
intel_dp->aux.ddc.dev.kobj.name);
|
||||
intel_connector_unregister(intel_connector);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_i2c_init(struct intel_dp *intel_dp,
|
||||
struct intel_connector *intel_connector, const char *name)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("i2c_init %s\n", name);
|
||||
intel_dp->algo.running = false;
|
||||
intel_dp->algo.address = 0;
|
||||
intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch;
|
||||
|
||||
memset(&intel_dp->adapter, '\0', sizeof(intel_dp->adapter));
|
||||
intel_dp->adapter.owner = THIS_MODULE;
|
||||
intel_dp->adapter.class = I2C_CLASS_DDC;
|
||||
strncpy(intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
|
||||
intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0';
|
||||
intel_dp->adapter.algo_data = &intel_dp->algo;
|
||||
intel_dp->adapter.dev.parent = intel_connector->base.dev->dev;
|
||||
|
||||
ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_link(&intel_connector->base.kdev->kobj,
|
||||
&intel_dp->adapter.dev.kobj,
|
||||
intel_dp->adapter.dev.kobj.name);
|
||||
|
||||
if (ret < 0)
|
||||
i2c_del_adapter(&intel_dp->adapter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_set_clock(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config, int link_bw)
|
||||
|
@ -1162,23 +1039,21 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
|
|||
return control;
|
||||
}
|
||||
|
||||
static void edp_panel_vdd_on(struct intel_dp *intel_dp)
|
||||
static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
u32 pp_stat_reg, pp_ctrl_reg;
|
||||
bool need_to_disable = !intel_dp->want_panel_vdd;
|
||||
|
||||
if (!is_edp(intel_dp))
|
||||
return;
|
||||
|
||||
WARN(intel_dp->want_panel_vdd,
|
||||
"eDP VDD already requested on\n");
|
||||
return false;
|
||||
|
||||
intel_dp->want_panel_vdd = true;
|
||||
|
||||
if (edp_have_panel_vdd(intel_dp))
|
||||
return;
|
||||
return need_to_disable;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
|
@ -1204,6 +1079,17 @@ static void edp_panel_vdd_on(struct intel_dp *intel_dp)
|
|||
DRM_DEBUG_KMS("eDP was not running\n");
|
||||
msleep(intel_dp->panel_power_up_delay);
|
||||
}
|
||||
|
||||
return need_to_disable;
|
||||
}
|
||||
|
||||
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
|
||||
{
|
||||
if (is_edp(intel_dp)) {
|
||||
bool vdd = _edp_panel_vdd_on(intel_dp);
|
||||
|
||||
WARN(!vdd, "eDP VDD already requested on\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
|
||||
|
@ -1330,6 +1216,8 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
|
|||
|
||||
edp_wait_backlight_off(intel_dp);
|
||||
|
||||
WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
|
||||
|
||||
pp = ironlake_get_pp_control(intel_dp);
|
||||
/* We need to switch off panel power _and_ force vdd, for otherwise some
|
||||
* panels get very unhappy and cease to work. */
|
||||
|
@ -1338,11 +1226,16 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
|
|||
|
||||
pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
|
||||
|
||||
intel_dp->want_panel_vdd = false;
|
||||
|
||||
I915_WRITE(pp_ctrl_reg, pp);
|
||||
POSTING_READ(pp_ctrl_reg);
|
||||
|
||||
intel_dp->last_power_cycle = jiffies;
|
||||
wait_panel_off(intel_dp);
|
||||
|
||||
/* We got a reference when we enabled the VDD. */
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
void intel_edp_backlight_on(struct intel_dp *intel_dp)
|
||||
|
@ -1459,8 +1352,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
|
|||
return;
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER,
|
||||
DP_SET_POWER_D3);
|
||||
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
|
||||
DP_SET_POWER_D3);
|
||||
if (ret != 1)
|
||||
DRM_DEBUG_DRIVER("failed to write sink power state\n");
|
||||
} else {
|
||||
|
@ -1469,9 +1362,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
|
|||
* time to wake up.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = intel_dp_aux_native_write_1(intel_dp,
|
||||
DP_SET_POWER,
|
||||
DP_SET_POWER_D0);
|
||||
ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
|
||||
DP_SET_POWER_D0);
|
||||
if (ret == 1)
|
||||
break;
|
||||
msleep(1);
|
||||
|
@ -1695,13 +1587,11 @@ static void intel_edp_psr_enable_sink(struct intel_dp *intel_dp)
|
|||
|
||||
/* Enable PSR in sink */
|
||||
if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT)
|
||||
intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
|
||||
DP_PSR_ENABLE &
|
||||
~DP_PSR_MAIN_LINK_ACTIVE);
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
|
||||
DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
|
||||
else
|
||||
intel_dp_aux_native_write_1(intel_dp, DP_PSR_EN_CFG,
|
||||
DP_PSR_ENABLE |
|
||||
DP_PSR_MAIN_LINK_ACTIVE);
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
|
||||
DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
|
||||
|
||||
/* Setup AUX registers */
|
||||
I915_WRITE(EDP_PSR_AUX_DATA1(dev), EDP_PSR_DPCD_COMMAND);
|
||||
|
@ -1876,11 +1766,10 @@ static void intel_disable_dp(struct intel_encoder *encoder)
|
|||
|
||||
/* Make sure the panel is off before trying to change the mode. But also
|
||||
* ensure that we have vdd while we switch off the panel. */
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_backlight_off(intel_dp);
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
||||
intel_edp_panel_off(intel_dp);
|
||||
edp_panel_vdd_off(intel_dp, true);
|
||||
|
||||
/* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
|
||||
if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
|
||||
|
@ -1910,7 +1799,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
|
|||
if (WARN_ON(dp_reg & DP_PORT_EN))
|
||||
return;
|
||||
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_panel_vdd_on(intel_dp);
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
intel_edp_panel_on(intel_dp);
|
||||
|
@ -2013,26 +1902,25 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
|
|||
/*
|
||||
* Native read with retry for link status and receiver capability reads for
|
||||
* cases where the sink may still be asleep.
|
||||
*
|
||||
* Sinks are *supposed* to come up within 1ms from an off state, but we're also
|
||||
* supposed to retry 3 times per the spec.
|
||||
*/
|
||||
static bool
|
||||
intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
|
||||
uint8_t *recv, int recv_bytes)
|
||||
static ssize_t
|
||||
intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
int ret, i;
|
||||
ssize_t ret;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Sinks are *supposed* to come up within 1ms from an off state,
|
||||
* but we're also supposed to retry 3 times per the spec.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
ret = intel_dp_aux_native_read(intel_dp, address, recv,
|
||||
recv_bytes);
|
||||
if (ret == recv_bytes)
|
||||
return true;
|
||||
ret = drm_dp_dpcd_read(aux, offset, buffer, size);
|
||||
if (ret == size)
|
||||
return ret;
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2042,10 +1930,10 @@ intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
|
|||
static bool
|
||||
intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
|
||||
{
|
||||
return intel_dp_aux_native_read_retry(intel_dp,
|
||||
DP_LANE0_1_STATUS,
|
||||
link_status,
|
||||
DP_LINK_STATUS_SIZE);
|
||||
return intel_dp_dpcd_read_wake(&intel_dp->aux,
|
||||
DP_LANE0_1_STATUS,
|
||||
link_status,
|
||||
DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2559,8 +2447,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
|
|||
len = intel_dp->lane_count + 1;
|
||||
}
|
||||
|
||||
ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_PATTERN_SET,
|
||||
buf, len);
|
||||
ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
|
||||
buf, len);
|
||||
|
||||
return ret == len;
|
||||
}
|
||||
|
@ -2589,9 +2477,8 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
|
|||
I915_WRITE(intel_dp->output_reg, *DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET,
|
||||
intel_dp->train_set,
|
||||
intel_dp->lane_count);
|
||||
ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
|
||||
intel_dp->train_set, intel_dp->lane_count);
|
||||
|
||||
return ret == intel_dp->lane_count;
|
||||
}
|
||||
|
@ -2647,11 +2534,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
|||
link_config[1] = intel_dp->lane_count;
|
||||
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
|
||||
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
|
||||
intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, link_config, 2);
|
||||
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
|
||||
|
||||
link_config[0] = 0;
|
||||
link_config[1] = DP_SET_ANSI_8B10B;
|
||||
intel_dp_aux_native_write(intel_dp, DP_DOWNSPREAD_CTRL, link_config, 2);
|
||||
drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
|
||||
|
||||
DP |= DP_PORT_EN;
|
||||
|
||||
|
@ -2894,8 +2781,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|||
|
||||
char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
|
||||
|
||||
if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
|
||||
sizeof(intel_dp->dpcd)) == 0)
|
||||
if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd,
|
||||
sizeof(intel_dp->dpcd)) < 0)
|
||||
return false; /* aux transfer failed */
|
||||
|
||||
hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
|
||||
|
@ -2908,9 +2795,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|||
/* Check if the panel supports PSR */
|
||||
memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
|
||||
if (is_edp(intel_dp)) {
|
||||
intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
|
||||
intel_dp->psr_dpcd,
|
||||
sizeof(intel_dp->psr_dpcd));
|
||||
intel_dp_dpcd_read_wake(&intel_dp->aux, DP_PSR_SUPPORT,
|
||||
intel_dp->psr_dpcd,
|
||||
sizeof(intel_dp->psr_dpcd));
|
||||
if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
|
||||
dev_priv->psr.sink_support = true;
|
||||
DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
|
||||
|
@ -2932,9 +2819,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
|
|||
if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
|
||||
return true; /* no per-port downstream info */
|
||||
|
||||
if (intel_dp_aux_native_read_retry(intel_dp, DP_DOWNSTREAM_PORT_0,
|
||||
intel_dp->downstream_ports,
|
||||
DP_MAX_DOWNSTREAM_PORTS) == 0)
|
||||
if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_DOWNSTREAM_PORT_0,
|
||||
intel_dp->downstream_ports,
|
||||
DP_MAX_DOWNSTREAM_PORTS) < 0)
|
||||
return false; /* downstream port status fetch failed */
|
||||
|
||||
return true;
|
||||
|
@ -2948,13 +2835,13 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
|
|||
if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
|
||||
return;
|
||||
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_panel_vdd_on(intel_dp);
|
||||
|
||||
if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3))
|
||||
if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_OUI, buf, 3) == 3)
|
||||
DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
|
||||
buf[0], buf[1], buf[2]);
|
||||
|
||||
if (intel_dp_aux_native_read_retry(intel_dp, DP_BRANCH_OUI, buf, 3))
|
||||
if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_BRANCH_OUI, buf, 3) == 3)
|
||||
DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
|
||||
buf[0], buf[1], buf[2]);
|
||||
|
||||
|
@ -2969,46 +2856,40 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
|
|||
to_intel_crtc(intel_dig_port->base.base.crtc);
|
||||
u8 buf[1];
|
||||
|
||||
if (!intel_dp_aux_native_read(intel_dp, DP_TEST_SINK_MISC, buf, 1))
|
||||
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, buf) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (!(buf[0] & DP_TEST_CRC_SUPPORTED))
|
||||
return -ENOTTY;
|
||||
|
||||
if (!intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK,
|
||||
DP_TEST_SINK_START))
|
||||
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
|
||||
DP_TEST_SINK_START) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Wait 2 vblanks to be sure we will have the correct CRC value */
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
if (!intel_dp_aux_native_read(intel_dp, DP_TEST_CRC_R_CR, crc, 6))
|
||||
if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
intel_dp_aux_native_write_1(intel_dp, DP_TEST_SINK, 0);
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = intel_dp_aux_native_read_retry(intel_dp,
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
sink_irq_vector, 1);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return intel_dp_dpcd_read_wake(&intel_dp->aux,
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
sink_irq_vector, 1) == 1;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_handle_test_request(struct intel_dp *intel_dp)
|
||||
{
|
||||
/* NAK by default */
|
||||
intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_NAK);
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3047,9 +2928,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
|
|||
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
|
||||
intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) {
|
||||
/* Clear interrupt source */
|
||||
intel_dp_aux_native_write_1(intel_dp,
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
sink_irq_vector);
|
||||
drm_dp_dpcd_writeb(&intel_dp->aux,
|
||||
DP_DEVICE_SERVICE_IRQ_VECTOR,
|
||||
sink_irq_vector);
|
||||
|
||||
if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
|
||||
intel_dp_handle_test_request(intel_dp);
|
||||
|
@ -3084,15 +2965,17 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
|
|||
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
|
||||
intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) {
|
||||
uint8_t reg;
|
||||
if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT,
|
||||
®, 1))
|
||||
|
||||
if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_COUNT,
|
||||
®, 1) < 0)
|
||||
return connector_status_unknown;
|
||||
|
||||
return DP_GET_SINK_COUNT(reg) ? connector_status_connected
|
||||
: connector_status_disconnected;
|
||||
}
|
||||
|
||||
/* If no HPD, poke DDC gently */
|
||||
if (drm_probe_ddc(&intel_dp->adapter))
|
||||
if (drm_probe_ddc(&intel_dp->aux.ddc))
|
||||
return connector_status_connected;
|
||||
|
||||
/* Well we tried, say unknown for unreliable port types */
|
||||
|
@ -3260,7 +3143,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
|
|||
if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
|
||||
intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
|
||||
} else {
|
||||
edid = intel_dp_get_edid(connector, &intel_dp->adapter);
|
||||
edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
|
||||
if (edid) {
|
||||
intel_dp->has_audio = drm_detect_monitor_audio(edid);
|
||||
kfree(edid);
|
||||
|
@ -3296,7 +3179,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
|
|||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter);
|
||||
ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc);
|
||||
intel_display_power_put(dev_priv, power_domain);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -3329,7 +3212,7 @@ intel_dp_detect_audio(struct drm_connector *connector)
|
|||
power_domain = intel_display_port_power_domain(intel_encoder);
|
||||
intel_display_power_get(dev_priv, power_domain);
|
||||
|
||||
edid = intel_dp_get_edid(connector, &intel_dp->adapter);
|
||||
edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
|
||||
if (edid) {
|
||||
has_audio = drm_detect_monitor_audio(edid);
|
||||
kfree(edid);
|
||||
|
@ -3451,7 +3334,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
|
|||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
|
||||
i2c_del_adapter(&intel_dp->adapter);
|
||||
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
|
||||
drm_encoder_cleanup(encoder);
|
||||
if (is_edp(intel_dp)) {
|
||||
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
|
||||
|
@ -3745,7 +3628,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
|
|||
return true;
|
||||
|
||||
/* Cache DPCD and EDID for edp. */
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
intel_edp_panel_vdd_on(intel_dp);
|
||||
has_dpcd = intel_dp_get_dpcd(intel_dp);
|
||||
edp_panel_vdd_off(intel_dp, false);
|
||||
|
||||
|
@ -3764,7 +3647,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
|
|||
intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
edid = drm_get_edid(connector, &intel_dp->adapter);
|
||||
edid = drm_get_edid(connector, &intel_dp->aux.ddc);
|
||||
if (edid) {
|
||||
if (drm_add_edid_modes(connector, edid)) {
|
||||
drm_mode_connector_update_edid_property(connector,
|
||||
|
@ -3813,8 +3696,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
enum port port = intel_dig_port->port;
|
||||
struct edp_power_seq power_seq = { 0 };
|
||||
const char *name = NULL;
|
||||
int type, error;
|
||||
int type;
|
||||
|
||||
/* intel_dp vfuncs */
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
|
@ -3867,43 +3749,19 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
|||
intel_connector->get_hw_state = intel_connector_get_hw_state;
|
||||
intel_connector->unregister = intel_dp_connector_unregister;
|
||||
|
||||
intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
|
||||
if (HAS_DDI(dev)) {
|
||||
switch (intel_dig_port->port) {
|
||||
case PORT_A:
|
||||
intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_B:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
/* Set up the hotplug pin. */
|
||||
switch (port) {
|
||||
case PORT_A:
|
||||
intel_encoder->hpd_pin = HPD_PORT_A;
|
||||
name = "DPDDC-A";
|
||||
break;
|
||||
case PORT_B:
|
||||
intel_encoder->hpd_pin = HPD_PORT_B;
|
||||
name = "DPDDC-B";
|
||||
break;
|
||||
case PORT_C:
|
||||
intel_encoder->hpd_pin = HPD_PORT_C;
|
||||
name = "DPDDC-C";
|
||||
break;
|
||||
case PORT_D:
|
||||
intel_encoder->hpd_pin = HPD_PORT_D;
|
||||
name = "DPDDC-D";
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
@ -3914,14 +3772,12 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
|||
intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
|
||||
}
|
||||
|
||||
error = intel_dp_i2c_init(intel_dp, intel_connector, name);
|
||||
WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
|
||||
error, port_name(port));
|
||||
intel_dp_aux_init(intel_dp, intel_connector);
|
||||
|
||||
intel_dp->psr_setup_done = false;
|
||||
|
||||
if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
|
||||
i2c_del_adapter(&intel_dp->adapter);
|
||||
drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
|
||||
if (is_edp(intel_dp)) {
|
||||
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
@ -3991,7 +3847,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
|
|||
|
||||
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
intel_encoder->hot_plug = intel_dp_hot_plug;
|
||||
|
||||
if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
|
||||
|
|
|
@ -78,6 +78,12 @@
|
|||
#define MAX_OUTPUTS 6
|
||||
/* maximum connectors per crtcs in the mode set */
|
||||
|
||||
/* Maximum cursor sizes */
|
||||
#define GEN2_CURSOR_WIDTH 64
|
||||
#define GEN2_CURSOR_HEIGHT 64
|
||||
#define CURSOR_WIDTH 256
|
||||
#define CURSOR_HEIGHT 256
|
||||
|
||||
#define INTEL_I2C_BUS_DVO 1
|
||||
#define INTEL_I2C_BUS_SDVO 2
|
||||
|
||||
|
@ -113,6 +119,7 @@ struct intel_fbdev {
|
|||
struct intel_framebuffer *fb;
|
||||
struct list_head fbdev_list;
|
||||
struct drm_display_mode *our_mode;
|
||||
int preferred_bpp;
|
||||
};
|
||||
|
||||
struct intel_encoder {
|
||||
|
@ -124,11 +131,7 @@ struct intel_encoder {
|
|||
struct intel_crtc *new_crtc;
|
||||
|
||||
int type;
|
||||
/*
|
||||
* Intel hw has only one MUX where encoders could be clone, hence a
|
||||
* simple flag is enough to compute the possible_clones mask.
|
||||
*/
|
||||
bool cloneable;
|
||||
unsigned int cloneable;
|
||||
bool connectors_active;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
bool (*compute_config)(struct intel_encoder *,
|
||||
|
@ -218,6 +221,12 @@ typedef struct dpll {
|
|||
int p;
|
||||
} intel_clock_t;
|
||||
|
||||
struct intel_plane_config {
|
||||
bool tiled;
|
||||
int size;
|
||||
u32 base;
|
||||
};
|
||||
|
||||
struct intel_crtc_config {
|
||||
/**
|
||||
* quirks - bitfield with hw state readout quirks
|
||||
|
@ -364,8 +373,10 @@ struct intel_crtc {
|
|||
uint32_t cursor_addr;
|
||||
int16_t cursor_x, cursor_y;
|
||||
int16_t cursor_width, cursor_height;
|
||||
int16_t max_cursor_width, max_cursor_height;
|
||||
bool cursor_visible;
|
||||
|
||||
struct intel_plane_config plane_config;
|
||||
struct intel_crtc_config config;
|
||||
struct intel_crtc_config *new_config;
|
||||
bool new_enabled;
|
||||
|
@ -485,8 +496,7 @@ struct intel_dp {
|
|||
uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
|
||||
uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
|
||||
uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
|
||||
struct i2c_adapter adapter;
|
||||
struct i2c_algo_dp_aux_data algo;
|
||||
struct drm_dp_aux aux;
|
||||
uint8_t train_set[4];
|
||||
int panel_power_up_delay;
|
||||
int panel_power_down_delay;
|
||||
|
@ -618,8 +628,8 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
|||
void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
||||
void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
||||
void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
|
||||
void hsw_pc8_disable_interrupts(struct drm_device *dev);
|
||||
void hsw_pc8_restore_interrupts(struct drm_device *dev);
|
||||
void hsw_runtime_pm_disable_interrupts(struct drm_device *dev);
|
||||
void hsw_runtime_pm_restore_interrupts(struct drm_device *dev);
|
||||
|
||||
|
||||
/* intel_crt.c */
|
||||
|
@ -722,9 +732,8 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
|
|||
unsigned int bpp,
|
||||
unsigned int pitch);
|
||||
void intel_display_handle_reset(struct drm_device *dev);
|
||||
void hsw_enable_pc8_work(struct work_struct *__work);
|
||||
void hsw_enable_package_c8(struct drm_i915_private *dev_priv);
|
||||
void hsw_disable_package_c8(struct drm_i915_private *dev_priv);
|
||||
void hsw_enable_pc8(struct drm_i915_private *dev_priv);
|
||||
void hsw_disable_pc8(struct drm_i915_private *dev_priv);
|
||||
void intel_dp_get_m_n(struct intel_crtc *crtc,
|
||||
struct intel_crtc_config *pipe_config);
|
||||
int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
|
||||
|
@ -740,6 +749,7 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder);
|
|||
int valleyview_get_vco(struct drm_i915_private *dev_priv);
|
||||
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
|
||||
struct intel_crtc_config *pipe_config);
|
||||
int intel_format_to_fourcc(int format);
|
||||
|
||||
/* intel_dp.c */
|
||||
void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
|
||||
|
@ -757,6 +767,7 @@ bool intel_dp_compute_config(struct intel_encoder *encoder,
|
|||
bool intel_dp_is_edp(struct drm_device *dev, enum port port);
|
||||
void intel_edp_backlight_on(struct intel_dp *intel_dp);
|
||||
void intel_edp_backlight_off(struct intel_dp *intel_dp);
|
||||
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
|
||||
void intel_edp_panel_on(struct intel_dp *intel_dp);
|
||||
void intel_edp_panel_off(struct intel_dp *intel_dp);
|
||||
void intel_edp_psr_enable(struct intel_dp *intel_dp);
|
||||
|
|
|
@ -620,7 +620,7 @@ bool intel_dsi_init(struct drm_device *dev)
|
|||
intel_encoder->type = INTEL_OUTPUT_DSI;
|
||||
intel_encoder->crtc_mask = (1 << 0); /* XXX */
|
||||
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
|
||||
|
|
|
@ -522,14 +522,15 @@ void intel_dvo_init(struct drm_device *dev)
|
|||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
switch (dvo->type) {
|
||||
case INTEL_DVO_CHIP_TMDS:
|
||||
intel_encoder->cloneable = true;
|
||||
intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
|
||||
(1 << INTEL_OUTPUT_DVO);
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DVII);
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
break;
|
||||
case INTEL_DVO_CHIP_LVDS:
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
|
|
|
@ -128,6 +128,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
|||
struct drm_framebuffer *fb;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int size, ret;
|
||||
bool prealloc = false;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
|
@ -139,6 +140,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
|||
intel_fb = ifbdev->fb;
|
||||
} else {
|
||||
DRM_DEBUG_KMS("re-using BIOS fb\n");
|
||||
prealloc = true;
|
||||
sizes->fb_width = intel_fb->base.width;
|
||||
sizes->fb_height = intel_fb->base.height;
|
||||
}
|
||||
|
@ -200,7 +202,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
|||
* If the object is stolen however, it will be full of whatever
|
||||
* garbage was left in there.
|
||||
*/
|
||||
if (ifbdev->fb->obj->stolen)
|
||||
if (ifbdev->fb->obj->stolen && !prealloc)
|
||||
memset_io(info->screen_base, 0, info->screen_size);
|
||||
|
||||
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
|
||||
|
@ -454,27 +456,149 @@ static void intel_fbdev_destroy(struct drm_device *dev,
|
|||
drm_framebuffer_remove(&ifbdev->fb->base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
|
||||
* The core display code will have read out the current plane configuration,
|
||||
* so we use that to figure out if there's an object for us to use as the
|
||||
* fb, and if so, we re-use it for the fbdev configuration.
|
||||
*
|
||||
* Note we only support a single fb shared across pipes for boot (mostly for
|
||||
* fbcon), so we just find the biggest and use that.
|
||||
*/
|
||||
static bool intel_fbdev_init_bios(struct drm_device *dev,
|
||||
struct intel_fbdev *ifbdev)
|
||||
{
|
||||
struct intel_framebuffer *fb = NULL;
|
||||
struct drm_crtc *crtc;
|
||||
struct intel_crtc *intel_crtc;
|
||||
struct intel_plane_config *plane_config = NULL;
|
||||
unsigned int max_size = 0;
|
||||
|
||||
if (!i915.fastboot)
|
||||
return false;
|
||||
|
||||
/* Find the largest fb */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
if (!intel_crtc->active || !crtc->primary->fb) {
|
||||
DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (intel_crtc->plane_config.size > max_size) {
|
||||
DRM_DEBUG_KMS("found possible fb from plane %c\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
plane_config = &intel_crtc->plane_config;
|
||||
fb = to_intel_framebuffer(crtc->primary->fb);
|
||||
max_size = plane_config->size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Now make sure all the pipes will fit into it */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
unsigned int cur_size;
|
||||
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
if (!intel_crtc->active) {
|
||||
DRM_DEBUG_KMS("pipe %c not active, skipping\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
continue;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
|
||||
pipe_name(intel_crtc->pipe));
|
||||
|
||||
/*
|
||||
* See if the plane fb we found above will fit on this
|
||||
* pipe. Note we need to use the selected fb's bpp rather
|
||||
* than the current pipe's, since they could be different.
|
||||
*/
|
||||
cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay *
|
||||
intel_crtc->config.adjusted_mode.crtc_vdisplay;
|
||||
DRM_DEBUG_KMS("pipe %c area: %d\n", pipe_name(intel_crtc->pipe),
|
||||
cur_size);
|
||||
cur_size *= fb->base.bits_per_pixel / 8;
|
||||
DRM_DEBUG_KMS("total size %d (bpp %d)\n", cur_size,
|
||||
fb->base.bits_per_pixel / 8);
|
||||
|
||||
if (cur_size > max_size) {
|
||||
DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
|
||||
pipe_name(intel_crtc->pipe),
|
||||
cur_size, max_size);
|
||||
plane_config = NULL;
|
||||
fb = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
|
||||
pipe_name(intel_crtc->pipe),
|
||||
max_size, cur_size);
|
||||
}
|
||||
|
||||
if (!fb) {
|
||||
DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ifbdev->preferred_bpp = fb->base.bits_per_pixel;
|
||||
ifbdev->fb = fb;
|
||||
|
||||
drm_framebuffer_reference(&ifbdev->fb->base);
|
||||
|
||||
/* Final pass to check if any active pipes don't have fbs */
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
if (!intel_crtc->active)
|
||||
continue;
|
||||
|
||||
WARN(!crtc->primary->fb,
|
||||
"re-used BIOS config but lost an fb on crtc %d\n",
|
||||
crtc->base.id);
|
||||
}
|
||||
|
||||
|
||||
DRM_DEBUG_KMS("using BIOS fb for initial console\n");
|
||||
return true;
|
||||
|
||||
out:
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int intel_fbdev_init(struct drm_device *dev)
|
||||
{
|
||||
struct intel_fbdev *ifbdev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL);
|
||||
if (!ifbdev)
|
||||
if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
|
||||
return -ENODEV;
|
||||
|
||||
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
|
||||
if (ifbdev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_priv->fbdev = ifbdev;
|
||||
ifbdev->helper.funcs = &intel_fb_helper_funcs;
|
||||
if (!intel_fbdev_init_bios(dev, ifbdev))
|
||||
ifbdev->preferred_bpp = 32;
|
||||
|
||||
ret = drm_fb_helper_init(dev, &ifbdev->helper,
|
||||
INTEL_INFO(dev)->num_pipes,
|
||||
4);
|
||||
INTEL_INFO(dev)->num_pipes, 4);
|
||||
if (ret) {
|
||||
kfree(ifbdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->fbdev = ifbdev;
|
||||
drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
|
||||
|
||||
return 0;
|
||||
|
@ -483,9 +607,10 @@ int intel_fbdev_init(struct drm_device *dev)
|
|||
void intel_fbdev_initial_config(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_fbdev *ifbdev = dev_priv->fbdev;
|
||||
|
||||
/* Due to peculiar init order wrt to hpd handling this is separate. */
|
||||
drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
|
||||
drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
|
||||
}
|
||||
|
||||
void intel_fbdev_fini(struct drm_device *dev)
|
||||
|
@ -523,7 +648,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
|
|||
void intel_fbdev_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
|
||||
if (dev_priv->fbdev)
|
||||
drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
|
||||
}
|
||||
|
||||
void intel_fbdev_restore_mode(struct drm_device *dev)
|
||||
|
@ -531,7 +657,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
|
|||
int ret;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (INTEL_INFO(dev)->num_pipes == 0)
|
||||
if (!dev_priv->fbdev)
|
||||
return;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
|
|
@ -848,6 +848,30 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
struct intel_encoder *encoder;
|
||||
int count = 0, count_hdmi = 0;
|
||||
|
||||
if (!HAS_PCH_SPLIT(dev))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
|
||||
if (encoder->new_crtc != crtc)
|
||||
continue;
|
||||
|
||||
count_hdmi += encoder->type == INTEL_OUTPUT_HDMI;
|
||||
count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* HDMI 12bpc affects the clocks, so it's only possible
|
||||
* when not cloning with other encoder types.
|
||||
*/
|
||||
return count_hdmi > 0 && count_hdmi == count;
|
||||
}
|
||||
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_config *pipe_config)
|
||||
{
|
||||
|
@ -880,7 +904,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
|||
* within limits.
|
||||
*/
|
||||
if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
|
||||
clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
|
||||
clock_12bpc <= portclock_limit &&
|
||||
hdmi_12bpc_possible(encoder->new_crtc)) {
|
||||
DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
|
||||
desired_bpp = 12*3;
|
||||
|
||||
|
@ -1318,7 +1343,14 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
|
|||
|
||||
intel_encoder->type = INTEL_OUTPUT_HDMI;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
|
||||
/*
|
||||
* BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
|
||||
* to work on real hardware. And since g4x can send infoframes to
|
||||
* only one port anyway, nothing is lost by allowing it.
|
||||
*/
|
||||
if (IS_G4X(dev))
|
||||
intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
|
||||
|
||||
intel_dig_port->port = port;
|
||||
intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
|
||||
|
|
|
@ -963,7 +963,7 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
intel_encoder->type = INTEL_OUTPUT_LVDS;
|
||||
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
if (HAS_PCH_SPLIT(dev))
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
|
||||
else if (IS_GEN4(dev))
|
||||
|
|
|
@ -2085,7 +2085,7 @@ static void intel_print_wm_latency(struct drm_device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
static void intel_setup_wm_latency(struct drm_device *dev)
|
||||
static void ilk_setup_wm_latency(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
|
@ -2907,9 +2907,9 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
|
|||
* the hw runs at the minimal clock before selecting the desired
|
||||
* frequency, if the down threshold expires in that window we will not
|
||||
* receive a down interrupt. */
|
||||
limits = dev_priv->rps.max_delay << 24;
|
||||
if (val <= dev_priv->rps.min_delay)
|
||||
limits |= dev_priv->rps.min_delay << 16;
|
||||
limits = dev_priv->rps.max_freq_softlimit << 24;
|
||||
if (val <= dev_priv->rps.min_freq_softlimit)
|
||||
limits |= dev_priv->rps.min_freq_softlimit << 16;
|
||||
|
||||
return limits;
|
||||
}
|
||||
|
@ -2921,26 +2921,26 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
|
|||
new_power = dev_priv->rps.power;
|
||||
switch (dev_priv->rps.power) {
|
||||
case LOW_POWER:
|
||||
if (val > dev_priv->rps.rpe_delay + 1 && val > dev_priv->rps.cur_delay)
|
||||
if (val > dev_priv->rps.efficient_freq + 1 && val > dev_priv->rps.cur_freq)
|
||||
new_power = BETWEEN;
|
||||
break;
|
||||
|
||||
case BETWEEN:
|
||||
if (val <= dev_priv->rps.rpe_delay && val < dev_priv->rps.cur_delay)
|
||||
if (val <= dev_priv->rps.efficient_freq && val < dev_priv->rps.cur_freq)
|
||||
new_power = LOW_POWER;
|
||||
else if (val >= dev_priv->rps.rp0_delay && val > dev_priv->rps.cur_delay)
|
||||
else if (val >= dev_priv->rps.rp0_freq && val > dev_priv->rps.cur_freq)
|
||||
new_power = HIGH_POWER;
|
||||
break;
|
||||
|
||||
case HIGH_POWER:
|
||||
if (val < (dev_priv->rps.rp1_delay + dev_priv->rps.rp0_delay) >> 1 && val < dev_priv->rps.cur_delay)
|
||||
if (val < (dev_priv->rps.rp1_freq + dev_priv->rps.rp0_freq) >> 1 && val < dev_priv->rps.cur_freq)
|
||||
new_power = BETWEEN;
|
||||
break;
|
||||
}
|
||||
/* Max/min bins are special */
|
||||
if (val == dev_priv->rps.min_delay)
|
||||
if (val == dev_priv->rps.min_freq_softlimit)
|
||||
new_power = LOW_POWER;
|
||||
if (val == dev_priv->rps.max_delay)
|
||||
if (val == dev_priv->rps.max_freq_softlimit)
|
||||
new_power = HIGH_POWER;
|
||||
if (new_power == dev_priv->rps.power)
|
||||
return;
|
||||
|
@ -3014,10 +3014,10 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
|
||||
WARN_ON(val > dev_priv->rps.max_delay);
|
||||
WARN_ON(val < dev_priv->rps.min_delay);
|
||||
WARN_ON(val > dev_priv->rps.max_freq_softlimit);
|
||||
WARN_ON(val < dev_priv->rps.min_freq_softlimit);
|
||||
|
||||
if (val == dev_priv->rps.cur_delay) {
|
||||
if (val == dev_priv->rps.cur_freq) {
|
||||
/* min/max delay may still have been modified so be sure to
|
||||
* write the limits value */
|
||||
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
|
||||
|
@ -3045,7 +3045,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
|
|||
|
||||
POSTING_READ(GEN6_RPNSWREQ);
|
||||
|
||||
dev_priv->rps.cur_delay = val;
|
||||
dev_priv->rps.cur_freq = val;
|
||||
|
||||
trace_intel_gpu_freq_change(val * 50);
|
||||
}
|
||||
|
@ -3065,7 +3065,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
|
|||
* When we are idle. Drop to min voltage state.
|
||||
*/
|
||||
|
||||
if (dev_priv->rps.cur_delay <= dev_priv->rps.min_delay)
|
||||
if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
|
||||
return;
|
||||
|
||||
/* Mask turbo interrupt so that they will not come in between */
|
||||
|
@ -3082,10 +3082,10 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
|
|||
return;
|
||||
}
|
||||
|
||||
dev_priv->rps.cur_delay = dev_priv->rps.min_delay;
|
||||
dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
|
||||
|
||||
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
|
||||
dev_priv->rps.min_delay);
|
||||
dev_priv->rps.min_freq_softlimit);
|
||||
|
||||
if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
|
||||
& GENFREQSTATUS) == 0, 5))
|
||||
|
@ -3099,7 +3099,7 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
|
|||
/* Unmask Up interrupts */
|
||||
dev_priv->rps.rp_up_masked = true;
|
||||
gen6_set_pm_mask(dev_priv, GEN6_PM_RP_DOWN_THRESHOLD,
|
||||
dev_priv->rps.min_delay);
|
||||
dev_priv->rps.min_freq_softlimit);
|
||||
}
|
||||
|
||||
void gen6_rps_idle(struct drm_i915_private *dev_priv)
|
||||
|
@ -3111,7 +3111,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
|
|||
if (IS_VALLEYVIEW(dev))
|
||||
vlv_set_rps_idle(dev_priv);
|
||||
else
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
|
||||
dev_priv->rps.last_adj = 0;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
@ -3124,9 +3124,9 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv)
|
|||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
if (dev_priv->rps.enabled) {
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
|
||||
else
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
|
||||
dev_priv->rps.last_adj = 0;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
@ -3137,20 +3137,20 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
|
||||
WARN_ON(val > dev_priv->rps.max_delay);
|
||||
WARN_ON(val < dev_priv->rps.min_delay);
|
||||
WARN_ON(val > dev_priv->rps.max_freq_softlimit);
|
||||
WARN_ON(val < dev_priv->rps.min_freq_softlimit);
|
||||
|
||||
DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
|
||||
dev_priv->rps.cur_delay,
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
|
||||
dev_priv->rps.cur_freq,
|
||||
vlv_gpu_freq(dev_priv, val), val);
|
||||
|
||||
if (val == dev_priv->rps.cur_delay)
|
||||
if (val == dev_priv->rps.cur_freq)
|
||||
return;
|
||||
|
||||
vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
|
||||
|
||||
dev_priv->rps.cur_delay = val;
|
||||
dev_priv->rps.cur_freq = val;
|
||||
|
||||
trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
|
||||
}
|
||||
|
@ -3292,8 +3292,8 @@ static void gen8_enable_rps(struct drm_device *dev)
|
|||
|
||||
/* Docs recommend 900MHz, and 300 MHz respectively */
|
||||
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
|
||||
dev_priv->rps.max_delay << 24 |
|
||||
dev_priv->rps.min_delay << 16);
|
||||
dev_priv->rps.max_freq_softlimit << 24 |
|
||||
dev_priv->rps.min_freq_softlimit << 16);
|
||||
|
||||
I915_WRITE(GEN6_RP_UP_THRESHOLD, 7600000 / 128); /* 76ms busyness per EI, 90% */
|
||||
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 31300000 / 128); /* 313ms busyness per EI, 70%*/
|
||||
|
@ -3324,9 +3324,9 @@ static void gen6_enable_rps(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
u32 rp_state_cap, hw_max, hw_min;
|
||||
u32 rp_state_cap;
|
||||
u32 gt_perf_status;
|
||||
u32 rc6vids, pcu_mbox, rc6_mask = 0;
|
||||
u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
|
||||
u32 gtfifodbg;
|
||||
int rc6_mode;
|
||||
int i, ret;
|
||||
|
@ -3352,20 +3352,23 @@ static void gen6_enable_rps(struct drm_device *dev)
|
|||
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
|
||||
gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
|
||||
|
||||
/* In units of 50MHz */
|
||||
dev_priv->rps.hw_max = hw_max = rp_state_cap & 0xff;
|
||||
hw_min = (rp_state_cap >> 16) & 0xff;
|
||||
dev_priv->rps.rp1_delay = (rp_state_cap >> 8) & 0xff;
|
||||
dev_priv->rps.rp0_delay = (rp_state_cap >> 0) & 0xff;
|
||||
dev_priv->rps.rpe_delay = dev_priv->rps.rp1_delay;
|
||||
dev_priv->rps.cur_delay = 0;
|
||||
/* All of these values are in units of 50MHz */
|
||||
dev_priv->rps.cur_freq = 0;
|
||||
/* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */
|
||||
dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff;
|
||||
dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff;
|
||||
dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff;
|
||||
/* XXX: only BYT has a special efficient freq */
|
||||
dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
|
||||
/* hw_max = RP0 until we check for overclocking */
|
||||
dev_priv->rps.max_freq = dev_priv->rps.rp0_freq;
|
||||
|
||||
/* Preserve min/max settings in case of re-init */
|
||||
if (dev_priv->rps.max_delay == 0)
|
||||
dev_priv->rps.max_delay = hw_max;
|
||||
if (dev_priv->rps.max_freq_softlimit == 0)
|
||||
dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
|
||||
|
||||
if (dev_priv->rps.min_delay == 0)
|
||||
dev_priv->rps.min_delay = hw_min;
|
||||
if (dev_priv->rps.min_freq_softlimit == 0)
|
||||
dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
|
||||
|
||||
/* disable the counters and set deterministic thresholds */
|
||||
I915_WRITE(GEN6_RC_CONTROL, 0);
|
||||
|
@ -3414,21 +3417,19 @@ static void gen6_enable_rps(struct drm_device *dev)
|
|||
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
|
||||
|
||||
ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0);
|
||||
if (!ret) {
|
||||
pcu_mbox = 0;
|
||||
ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
|
||||
if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
|
||||
DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
|
||||
(dev_priv->rps.max_delay & 0xff) * 50,
|
||||
(pcu_mbox & 0xff) * 50);
|
||||
dev_priv->rps.hw_max = pcu_mbox & 0xff;
|
||||
}
|
||||
} else {
|
||||
if (ret)
|
||||
DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
|
||||
|
||||
ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
|
||||
if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
|
||||
DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
|
||||
(dev_priv->rps.max_freq_softlimit & 0xff) * 50,
|
||||
(pcu_mbox & 0xff) * 50);
|
||||
dev_priv->rps.max_freq = pcu_mbox & 0xff;
|
||||
}
|
||||
|
||||
dev_priv->rps.power = HIGH_POWER; /* force a reset */
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
|
||||
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
|
||||
|
||||
gen6_enable_rps_interrupts(dev);
|
||||
|
||||
|
@ -3484,9 +3485,9 @@ void gen6_update_ring_freq(struct drm_device *dev)
|
|||
* to use for memory access. We do this by specifying the IA frequency
|
||||
* the PCU should use as a reference to determine the ring frequency.
|
||||
*/
|
||||
for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay;
|
||||
for (gpu_freq = dev_priv->rps.max_freq_softlimit; gpu_freq >= dev_priv->rps.min_freq_softlimit;
|
||||
gpu_freq--) {
|
||||
int diff = dev_priv->rps.max_delay - gpu_freq;
|
||||
int diff = dev_priv->rps.max_freq_softlimit - gpu_freq;
|
||||
unsigned int ia_freq = 0, ring_freq = 0;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 8) {
|
||||
|
@ -3597,7 +3598,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_ring_buffer *ring;
|
||||
u32 gtfifodbg, val, hw_max, hw_min, rc6_mode = 0;
|
||||
u32 gtfifodbg, val, rc6_mode = 0;
|
||||
int i;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
|
||||
|
@ -3652,38 +3653,39 @@ static void valleyview_enable_rps(struct drm_device *dev)
|
|||
DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
|
||||
DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
|
||||
|
||||
dev_priv->rps.cur_delay = (val >> 8) & 0xff;
|
||||
dev_priv->rps.cur_freq = (val >> 8) & 0xff;
|
||||
DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
|
||||
dev_priv->rps.cur_delay);
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
|
||||
dev_priv->rps.cur_freq);
|
||||
|
||||
dev_priv->rps.hw_max = hw_max = valleyview_rps_max_freq(dev_priv);
|
||||
dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
|
||||
dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
|
||||
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, hw_max),
|
||||
hw_max);
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
|
||||
dev_priv->rps.max_freq);
|
||||
|
||||
dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
|
||||
dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
|
||||
DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
|
||||
dev_priv->rps.rpe_delay);
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
|
||||
dev_priv->rps.efficient_freq);
|
||||
|
||||
hw_min = valleyview_rps_min_freq(dev_priv);
|
||||
dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
|
||||
DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, hw_min),
|
||||
hw_min);
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
|
||||
dev_priv->rps.min_freq);
|
||||
|
||||
/* Preserve min/max settings in case of re-init */
|
||||
if (dev_priv->rps.max_delay == 0)
|
||||
dev_priv->rps.max_delay = hw_max;
|
||||
if (dev_priv->rps.max_freq_softlimit == 0)
|
||||
dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
|
||||
|
||||
if (dev_priv->rps.min_delay == 0)
|
||||
dev_priv->rps.min_delay = hw_min;
|
||||
if (dev_priv->rps.min_freq_softlimit == 0)
|
||||
dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
|
||||
|
||||
DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
|
||||
dev_priv->rps.rpe_delay);
|
||||
vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
|
||||
dev_priv->rps.efficient_freq);
|
||||
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
|
||||
valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
|
||||
|
||||
dev_priv->rps.rp_up_masked = false;
|
||||
dev_priv->rps.rp_down_masked = false;
|
||||
|
@ -4124,7 +4126,7 @@ static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
|
|||
|
||||
assert_spin_locked(&mchdev_lock);
|
||||
|
||||
pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_delay * 4));
|
||||
pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_freq * 4));
|
||||
pxvid = (pxvid >> 24) & 0x7f;
|
||||
ext_v = pvid_to_extvid(dev_priv, pxvid);
|
||||
|
||||
|
@ -5345,8 +5347,6 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
|
|||
bool is_enabled, enable_requested;
|
||||
uint32_t tmp;
|
||||
|
||||
WARN_ON(dev_priv->pc8.enabled);
|
||||
|
||||
tmp = I915_READ(HSW_PWR_WELL_DRIVER);
|
||||
is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
|
||||
enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
|
||||
|
@ -5391,7 +5391,6 @@ static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
|
|||
static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
|
||||
struct i915_power_well *power_well)
|
||||
{
|
||||
hsw_disable_package_c8(dev_priv);
|
||||
hsw_set_power_well(dev_priv, power_well, true);
|
||||
}
|
||||
|
||||
|
@ -5399,7 +5398,6 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
|
|||
struct i915_power_well *power_well)
|
||||
{
|
||||
hsw_set_power_well(dev_priv, power_well, false);
|
||||
hsw_enable_package_c8(dev_priv);
|
||||
}
|
||||
|
||||
static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
|
||||
|
@ -5577,6 +5575,8 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
|
|||
struct i915_power_well *power_well;
|
||||
int i;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
power_domains = &dev_priv->power_domains;
|
||||
|
||||
mutex_lock(&power_domains->lock);
|
||||
|
@ -5621,6 +5621,8 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
|
||||
mutex_unlock(&power_domains->lock);
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
static struct i915_power_domains *hsw_pwr;
|
||||
|
@ -5884,15 +5886,14 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
|
|||
intel_power_domains_resume(dev_priv);
|
||||
}
|
||||
|
||||
/* Disables PC8 so we can use the GMBUS and DP AUX interrupts. */
|
||||
void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
hsw_disable_package_c8(dev_priv);
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
}
|
||||
|
||||
void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
hsw_enable_package_c8(dev_priv);
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
|
||||
|
@ -5924,8 +5925,6 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
|
|||
struct drm_device *dev = dev_priv->dev;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
|
||||
dev_priv->pm.suspended = false;
|
||||
|
||||
if (!HAS_RUNTIME_PM(dev))
|
||||
return;
|
||||
|
||||
|
@ -5934,6 +5933,8 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
|
|||
pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
|
||||
pm_runtime_mark_last_busy(device);
|
||||
pm_runtime_use_autosuspend(device);
|
||||
|
||||
pm_runtime_put_autosuspend(device);
|
||||
}
|
||||
|
||||
void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
|
||||
|
@ -5985,7 +5986,7 @@ void intel_init_pm(struct drm_device *dev)
|
|||
|
||||
/* For FIFO watermark updates */
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
intel_setup_wm_latency(dev);
|
||||
ilk_setup_wm_latency(dev);
|
||||
|
||||
if ((IS_GEN5(dev) && dev_priv->wm.pri_latency[1] &&
|
||||
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
|
||||
|
@ -6156,12 +6157,9 @@ void intel_pm_setup(struct drm_device *dev)
|
|||
|
||||
mutex_init(&dev_priv->rps.hw_lock);
|
||||
|
||||
mutex_init(&dev_priv->pc8.lock);
|
||||
dev_priv->pc8.requirements_met = false;
|
||||
dev_priv->pc8.irqs_disabled = false;
|
||||
dev_priv->pc8.enabled = false;
|
||||
dev_priv->pc8.disable_count = 1; /* requirements_met */
|
||||
INIT_DELAYED_WORK(&dev_priv->pc8.enable_work, hsw_enable_pc8_work);
|
||||
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
|
||||
intel_gen6_powersave_work);
|
||||
|
||||
dev_priv->pm.suspended = false;
|
||||
dev_priv->pm.irqs_disabled = false;
|
||||
}
|
||||
|
|
|
@ -440,15 +440,17 @@ static int init_ring_common(struct intel_ring_buffer *ring)
|
|||
|
||||
gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev))
|
||||
intel_ring_setup_status_page(ring);
|
||||
else
|
||||
ring_setup_phys_status_page(ring);
|
||||
|
||||
/* Stop the ring if it's running. */
|
||||
I915_WRITE_CTL(ring, 0);
|
||||
I915_WRITE_HEAD(ring, 0);
|
||||
ring->write_tail(ring, 0);
|
||||
if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000))
|
||||
DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev))
|
||||
intel_ring_setup_status_page(ring);
|
||||
else
|
||||
ring_setup_phys_status_page(ring);
|
||||
|
||||
head = I915_READ_HEAD(ring) & HEAD_ADDR;
|
||||
|
||||
|
@ -979,9 +981,19 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
|
|||
I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
|
||||
POSTING_READ(mmio);
|
||||
|
||||
/* Flush the TLB for this page */
|
||||
if (INTEL_INFO(dev)->gen >= 6) {
|
||||
/*
|
||||
* Flush the TLB for this page
|
||||
*
|
||||
* FIXME: These two bits have disappeared on gen8, so a question
|
||||
* arises: do we still need this and if so how should we go about
|
||||
* invalidating the TLB?
|
||||
*/
|
||||
if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
|
||||
u32 reg = RING_INSTPM(ring->mmio_base);
|
||||
|
||||
/* ring should be idle before issuing a sync flush*/
|
||||
WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
|
||||
|
||||
I915_WRITE(reg,
|
||||
_MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
|
||||
INSTPM_SYNC_FLUSH));
|
||||
|
|
|
@ -33,6 +33,8 @@ struct intel_hw_status_page {
|
|||
#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
|
||||
#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
|
||||
|
||||
#define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base))
|
||||
|
||||
enum intel_ring_hangcheck_action {
|
||||
HANGCHECK_IDLE = 0,
|
||||
HANGCHECK_WAIT,
|
||||
|
|
|
@ -1461,7 +1461,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
|
|||
u32 temp;
|
||||
bool input1, input2;
|
||||
int i;
|
||||
u8 status;
|
||||
bool success;
|
||||
|
||||
temp = I915_READ(intel_sdvo->sdvo_reg);
|
||||
if ((temp & SDVO_ENABLE) == 0) {
|
||||
|
@ -1475,12 +1475,12 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
|
|||
for (i = 0; i < 2; i++)
|
||||
intel_wait_for_vblank(dev, intel_crtc->pipe);
|
||||
|
||||
status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
|
||||
success = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
|
||||
/* Warn if the device reported failure to sync.
|
||||
* A lot of SDVO devices fail to notify of sync, but it's
|
||||
* a given it the status is a success, we succeeded.
|
||||
*/
|
||||
if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
|
||||
if (success && !input1) {
|
||||
DRM_DEBUG_KMS("First %s output reported failure to "
|
||||
"sync\n", SDVO_NAME(intel_sdvo));
|
||||
}
|
||||
|
@ -3032,7 +3032,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
|
|||
* simplistic anyway to express such constraints, so just give up on
|
||||
* cloning for SDVO encoders.
|
||||
*/
|
||||
intel_sdvo->base.cloneable = false;
|
||||
intel_sdvo->base.cloneable = 0;
|
||||
|
||||
intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
|
||||
|
||||
|
|
|
@ -1639,9 +1639,8 @@ intel_tv_init(struct drm_device *dev)
|
|||
intel_connector_attach_encoder(intel_connector, intel_encoder);
|
||||
intel_encoder->type = INTEL_OUTPUT_TVOUT;
|
||||
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
||||
intel_encoder->cloneable = false;
|
||||
intel_encoder->cloneable = 0;
|
||||
intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
|
||||
intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
|
||||
intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
|
||||
|
||||
/* BIOS margin values */
|
||||
|
|
|
@ -280,12 +280,17 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv,
|
|||
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
|
||||
if (fw_engine & FORCEWAKE_RENDER &&
|
||||
--dev_priv->uncore.fw_rendercount != 0)
|
||||
fw_engine &= ~FORCEWAKE_RENDER;
|
||||
if (fw_engine & FORCEWAKE_MEDIA &&
|
||||
--dev_priv->uncore.fw_mediacount != 0)
|
||||
fw_engine &= ~FORCEWAKE_MEDIA;
|
||||
if (fw_engine & FORCEWAKE_RENDER) {
|
||||
WARN_ON(!dev_priv->uncore.fw_rendercount);
|
||||
if (--dev_priv->uncore.fw_rendercount != 0)
|
||||
fw_engine &= ~FORCEWAKE_RENDER;
|
||||
}
|
||||
|
||||
if (fw_engine & FORCEWAKE_MEDIA) {
|
||||
WARN_ON(!dev_priv->uncore.fw_mediacount);
|
||||
if (--dev_priv->uncore.fw_mediacount != 0)
|
||||
fw_engine &= ~FORCEWAKE_MEDIA;
|
||||
}
|
||||
|
||||
if (fw_engine)
|
||||
dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine);
|
||||
|
@ -301,6 +306,8 @@ static void gen6_force_wake_timer(unsigned long arg)
|
|||
assert_device_not_suspended(dev_priv);
|
||||
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
WARN_ON(!dev_priv->uncore.forcewake_count);
|
||||
|
||||
if (--dev_priv->uncore.forcewake_count == 0)
|
||||
dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
|
||||
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
||||
|
@ -308,9 +315,17 @@ static void gen6_force_wake_timer(unsigned long arg)
|
|||
intel_runtime_pm_put(dev_priv);
|
||||
}
|
||||
|
||||
static void intel_uncore_forcewake_reset(struct drm_device *dev)
|
||||
static void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
|
||||
del_timer_sync(&dev_priv->uncore.force_wake_timer);
|
||||
|
||||
/* Hold uncore.lock across reset to prevent any register access
|
||||
* with forcewake not set correctly
|
||||
*/
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
|
||||
if (IS_VALLEYVIEW(dev))
|
||||
vlv_force_wake_reset(dev_priv);
|
||||
|
@ -319,6 +334,35 @@ static void intel_uncore_forcewake_reset(struct drm_device *dev)
|
|||
|
||||
if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev))
|
||||
__gen7_gt_force_wake_mt_reset(dev_priv);
|
||||
|
||||
if (restore) { /* If reset with a user forcewake, try to restore */
|
||||
unsigned fw = 0;
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
if (dev_priv->uncore.fw_rendercount)
|
||||
fw |= FORCEWAKE_RENDER;
|
||||
|
||||
if (dev_priv->uncore.fw_mediacount)
|
||||
fw |= FORCEWAKE_MEDIA;
|
||||
} else {
|
||||
if (dev_priv->uncore.forcewake_count)
|
||||
fw = FORCEWAKE_ALL;
|
||||
}
|
||||
|
||||
if (fw)
|
||||
dev_priv->uncore.funcs.force_wake_get(dev_priv, fw);
|
||||
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev))
|
||||
dev_priv->uncore.fifo_count =
|
||||
__raw_i915_read32(dev_priv, GTFIFOCTL) &
|
||||
GT_FIFO_FREE_ENTRIES_MASK;
|
||||
} else {
|
||||
dev_priv->uncore.forcewake_count = 0;
|
||||
dev_priv->uncore.fw_rendercount = 0;
|
||||
dev_priv->uncore.fw_mediacount = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
||||
}
|
||||
|
||||
void intel_uncore_early_sanitize(struct drm_device *dev)
|
||||
|
@ -344,7 +388,7 @@ void intel_uncore_early_sanitize(struct drm_device *dev)
|
|||
__raw_i915_write32(dev_priv, GTFIFODBG,
|
||||
__raw_i915_read32(dev_priv, GTFIFODBG));
|
||||
|
||||
intel_uncore_forcewake_reset(dev);
|
||||
intel_uncore_forcewake_reset(dev, false);
|
||||
}
|
||||
|
||||
void intel_uncore_sanitize(struct drm_device *dev)
|
||||
|
@ -415,6 +459,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
|
|||
|
||||
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
WARN_ON(!dev_priv->uncore.forcewake_count);
|
||||
|
||||
if (--dev_priv->uncore.forcewake_count == 0) {
|
||||
dev_priv->uncore.forcewake_count++;
|
||||
delayed = true;
|
||||
|
@ -690,6 +736,8 @@ void intel_uncore_init(struct drm_device *dev)
|
|||
setup_timer(&dev_priv->uncore.force_wake_timer,
|
||||
gen6_force_wake_timer, (unsigned long)dev_priv);
|
||||
|
||||
intel_uncore_early_sanitize(dev);
|
||||
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get;
|
||||
dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put;
|
||||
|
@ -798,13 +846,9 @@ void intel_uncore_init(struct drm_device *dev)
|
|||
|
||||
void intel_uncore_fini(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
del_timer_sync(&dev_priv->uncore.force_wake_timer);
|
||||
|
||||
/* Paranoia: make sure we have disabled everything before we exit. */
|
||||
intel_uncore_sanitize(dev);
|
||||
intel_uncore_forcewake_reset(dev);
|
||||
intel_uncore_forcewake_reset(dev, false);
|
||||
}
|
||||
|
||||
static const struct register_whitelist {
|
||||
|
@ -953,13 +997,6 @@ static int gen6_do_reset(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
unsigned long irqflags;
|
||||
u32 fw_engine = 0;
|
||||
|
||||
/* Hold uncore.lock across reset to prevent any register access
|
||||
* with forcewake not set correctly
|
||||
*/
|
||||
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
||||
|
||||
/* Reset the chip */
|
||||
|
||||
|
@ -972,29 +1009,8 @@ static int gen6_do_reset(struct drm_device *dev)
|
|||
/* Spin waiting for the device to ack the reset request */
|
||||
ret = wait_for((__raw_i915_read32(dev_priv, GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
|
||||
|
||||
intel_uncore_forcewake_reset(dev);
|
||||
intel_uncore_forcewake_reset(dev, true);
|
||||
|
||||
/* If reset with a user forcewake, try to restore */
|
||||
if (IS_VALLEYVIEW(dev)) {
|
||||
if (dev_priv->uncore.fw_rendercount)
|
||||
fw_engine |= FORCEWAKE_RENDER;
|
||||
|
||||
if (dev_priv->uncore.fw_mediacount)
|
||||
fw_engine |= FORCEWAKE_MEDIA;
|
||||
} else {
|
||||
if (dev_priv->uncore.forcewake_count)
|
||||
fw_engine = FORCEWAKE_ALL;
|
||||
}
|
||||
|
||||
if (fw_engine)
|
||||
dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine);
|
||||
|
||||
if (IS_GEN6(dev) || IS_GEN7(dev))
|
||||
dev_priv->uncore.fifo_count =
|
||||
__raw_i915_read32(dev_priv, GTFIFOCTL) &
|
||||
GT_FIFO_FREE_ENTRIES_MASK;
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -438,6 +438,9 @@ struct drm_dp_aux_msg {
|
|||
* The .dev field should be set to a pointer to the device that implements
|
||||
* the AUX channel.
|
||||
*
|
||||
* The .name field may be used to specify the name of the I2C adapter. If set to
|
||||
* NULL, dev_name() of .dev will be used.
|
||||
*
|
||||
* Drivers provide a hardware-specific implementation of how transactions
|
||||
* are executed via the .transfer() function. A pointer to a drm_dp_aux_msg
|
||||
* structure describing the transaction is passed into this function. Upon
|
||||
|
@ -455,6 +458,7 @@ struct drm_dp_aux_msg {
|
|||
* should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
|
||||
*/
|
||||
struct drm_dp_aux {
|
||||
const char *name;
|
||||
struct i2c_adapter ddc;
|
||||
struct device *dev;
|
||||
|
||||
|
|
Loading…
Reference in a new issue