#define WATCH_LISTS 0
#define WATCH_GTT 0
-#define I915_GEM_PHYS_CURSOR_0 1
-#define I915_GEM_PHYS_CURSOR_1 2
-#define I915_GEM_PHYS_OVERLAY_REGS 3
-#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)
-
-struct drm_i915_gem_phys_object {
- int id;
- struct page **page_list;
- drm_dma_handle_t *handle;
- struct drm_i915_gem_object *cur_obj;
-};
-
struct opregion_header;
struct opregion_acpi;
struct opregion_swsci;
/** Bit 6 swizzling required for Y tiling */
uint32_t bit_6_swizzle_y;
- /* storage for physical objects */
- struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
-
/* accounting, useful for userland debugging */
spinlock_t object_stat_lock;
size_t object_memory;
unsigned int lvds_use_ssc:1;
unsigned int display_clock_mode:1;
unsigned int fdi_rx_polarity_inverted:1;
+ unsigned int has_mipi:1;
int lvds_ssc_freq;
unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
/* MIPI DSI */
struct {
+ u16 port;
u16 panel_id;
struct mipi_config *config;
struct mipi_pps_data *pps;
struct drm_file *pin_filp;
/** for phy allocated objects */
- struct drm_i915_gem_phys_object *phys_obj;
+ drm_dma_handle_t *phys_handle;
union {
struct i915_gem_userptr {
#define IS_ULT(dev) (IS_HSW_ULT(dev) || IS_BDW_ULT(dev))
#define IS_HSW_GT3(dev) (IS_HASWELL(dev) && \
((dev)->pdev->device & 0x00F0) == 0x0020)
+/* ULX machines are also considered ULT. */
+#define IS_HSW_ULX(dev) ((dev)->pdev->device == 0x0A0E || \
+ (dev)->pdev->device == 0x0A1E)
#define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
/*
#define PIN_MAPPABLE 0x1
#define PIN_NONBLOCK 0x2
#define PIN_GLOBAL 0x4
+#define PIN_OFFSET_BIAS 0x8
+#define PIN_OFFSET_MASK (~4095)
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
- unsigned flags);
+ uint64_t flags);
int __must_check i915_vma_unbind(struct i915_vma *vma);
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
u32 alignment,
struct intel_engine_cs *pipelined);
void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj);
-int i915_gem_attach_phys_object(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- int id,
+int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
int align);
-void i915_gem_detach_phys_object(struct drm_device *dev,
- struct drm_i915_gem_object *obj);
-void i915_gem_free_all_phys_object(struct drm_device *dev);
int i915_gem_open(struct drm_device *dev, struct drm_file *file);
void i915_gem_release(struct drm_device *dev, struct drm_file *file);
int min_size,
unsigned alignment,
unsigned cache_level,
+ unsigned long start,
+ unsigned long end,
unsigned flags);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
int i915_gem_evict_everything(struct drm_device *dev);
static void
i915_gem_object_retire(struct drm_i915_gem_object *obj);
-static int i915_gem_phys_pwrite(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pwrite *args,
- struct drm_file *file);
-
static void i915_gem_write_fence(struct drm_device *dev, int reg,
struct drm_i915_gem_object *obj);
static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
return 0;
}
+static void i915_gem_object_detach_phys(struct drm_i915_gem_object *obj)
+{
+ drm_dma_handle_t *phys = obj->phys_handle;
+
+ if (!phys)
+ return;
+
+ if (obj->madv == I915_MADV_WILLNEED) {
+ struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
+ char *vaddr = phys->vaddr;
+ int i;
+
+ for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
+ struct page *page = shmem_read_mapping_page(mapping, i);
+ if (!IS_ERR(page)) {
+ char *dst = kmap_atomic(page);
+ memcpy(dst, vaddr, PAGE_SIZE);
+ drm_clflush_virt_range(dst, PAGE_SIZE);
+ kunmap_atomic(dst);
+
+ set_page_dirty(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+ }
+ vaddr += PAGE_SIZE;
+ }
+ i915_gem_chipset_flush(obj->base.dev);
+ }
+
+#ifdef CONFIG_X86
+ set_memory_wb((unsigned long)phys->vaddr, phys->size / PAGE_SIZE);
+#endif
+ drm_pci_free(obj->base.dev, phys);
+ obj->phys_handle = NULL;
+}
+
+int
+i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
+ int align)
+{
+ drm_dma_handle_t *phys;
+ struct address_space *mapping;
+ char *vaddr;
+ int i;
+
+ if (obj->phys_handle) {
+ if ((unsigned long)obj->phys_handle->vaddr & (align -1))
+ return -EBUSY;
+
+ return 0;
+ }
+
+ if (obj->madv != I915_MADV_WILLNEED)
+ return -EFAULT;
+
+ if (obj->base.filp == NULL)
+ return -EINVAL;
+
+ /* create a new object */
+ phys = drm_pci_alloc(obj->base.dev, obj->base.size, align);
+ if (!phys)
+ return -ENOMEM;
+
+ vaddr = phys->vaddr;
+#ifdef CONFIG_X86
+ set_memory_wc((unsigned long)vaddr, phys->size / PAGE_SIZE);
+#endif
+ mapping = file_inode(obj->base.filp)->i_mapping;
+ for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
+ struct page *page;
+ char *src;
+
+ page = shmem_read_mapping_page(mapping, i);
+ if (IS_ERR(page)) {
+#ifdef CONFIG_X86
+ set_memory_wb((unsigned long)phys->vaddr, phys->size / PAGE_SIZE);
+#endif
+ drm_pci_free(obj->base.dev, phys);
+ return PTR_ERR(page);
+ }
+
+ src = kmap_atomic(page);
+ memcpy(vaddr, src, PAGE_SIZE);
+ kunmap_atomic(src);
+
+ mark_page_accessed(page);
+ page_cache_release(page);
+
+ vaddr += PAGE_SIZE;
+ }
+
+ obj->phys_handle = phys;
+ return 0;
+}
+
+static int
+i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
+ struct drm_i915_gem_pwrite *args,
+ struct drm_file *file_priv)
+{
+ struct drm_device *dev = obj->base.dev;
+ void *vaddr = obj->phys_handle->vaddr + args->offset;
+ char __user *user_data = to_user_ptr(args->data_ptr);
+
+ if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
+ unsigned long unwritten;
+
+ /* The physical object once assigned is fixed for the lifetime
+ * of the obj, so we can safely drop the lock and continue
+ * to access vaddr.
+ */
+ mutex_unlock(&dev->struct_mutex);
+ unwritten = copy_from_user(vaddr, user_data, args->size);
+ mutex_lock(&dev->struct_mutex);
+ if (unwritten)
+ return -EFAULT;
+ }
+
+ i915_gem_chipset_flush(dev);
+ return 0;
+}
+
void *i915_gem_object_alloc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
* pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client.
*/
- if (obj->phys_obj) {
- ret = i915_gem_phys_pwrite(dev, obj, args, file);
+ if (obj->phys_handle) {
+ ret = i915_gem_phys_pwrite(obj, args, file);
goto out;
}
/* Access to snoopable pages through the GTT is incoherent. */
if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) {
- ret = -EINVAL;
+ ret = -EFAULT;
goto unlock;
}
i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
unsigned alignment,
- unsigned flags)
+ uint64_t flags)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 size, fence_size, fence_alignment, unfenced_alignment;
- size_t gtt_max =
+ unsigned long start =
+ flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
+ unsigned long end =
flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total;
struct i915_vma *vma;
int ret;
/* If the object is bigger than the entire aperture, reject it early
* before evicting everything in a vain attempt to find space.
*/
- if (obj->base.size > gtt_max) {
- DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
+ if (obj->base.size > end) {
+ DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%lu\n",
obj->base.size,
flags & PIN_MAPPABLE ? "mappable" : "total",
- gtt_max);
+ end);
return ERR_PTR(-E2BIG);
}
search_free:
ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
size, alignment,
- obj->cache_level, 0, gtt_max,
+ obj->cache_level,
+ start, end,
DRM_MM_SEARCH_DEFAULT,
DRM_MM_CREATE_DEFAULT);
if (ret) {
ret = i915_gem_evict_something(dev, vm, size, alignment,
- obj->cache_level, flags);
+ obj->cache_level,
+ start, end,
+ flags);
if (ret == 0)
goto search_free;
return ret;
}
+static bool
+i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
+{
+ struct drm_i915_gem_object *obj = vma->obj;
+
+ if (alignment &&
+ vma->node.start & (alignment - 1))
+ return true;
+
+ if (flags & PIN_MAPPABLE && !obj->map_and_fenceable)
+ return true;
+
+ if (flags & PIN_OFFSET_BIAS &&
+ vma->node.start < (flags & PIN_OFFSET_MASK))
+ return true;
+
+ return false;
+}
+
int
i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
- unsigned flags)
+ uint64_t flags)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
struct i915_vma *vma;
if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
return -EBUSY;
- if ((alignment &&
- vma->node.start & (alignment - 1)) ||
- (flags & PIN_MAPPABLE && !obj->map_and_fenceable)) {
+ if (i915_vma_misplaced(vma, alignment, flags)) {
WARN(vma->pin_count,
"bo is already pinned with incorrect alignment:"
" offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
" obj->map_and_fenceable=%d\n",
i915_gem_obj_offset(obj, vm), alignment,
- flags & PIN_MAPPABLE,
+ !!(flags & PIN_MAPPABLE),
obj->map_and_fenceable);
ret = i915_vma_unbind(vma);
if (ret)
trace_i915_gem_object_destroy(obj);
- if (obj->phys_obj)
- i915_gem_detach_phys_object(dev, obj);
-
list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
int ret;
}
}
+ i915_gem_object_detach_phys(obj);
+
/* Stolen objects don't hold a ref, but do hold pin count. Fix that up
* before progressing. */
if (obj->stolen)
init_waitqueue_head(&dev_priv->gpu_error.reset_queue);
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
- if (IS_GEN3(dev)) {
+ if (!drm_core_check_feature(dev, DRIVER_MODESET) && IS_GEN3(dev)) {
I915_WRITE(MI_ARB_STATE,
_MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
}
register_oom_notifier(&dev_priv->mm.oom_notifier);
}
-/*
- * Create a physically contiguous memory object for this object
- * e.g. for cursor + overlay regs
- */
-static int i915_gem_init_phys_object(struct drm_device *dev,
- int id, int size, int align)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_phys_object *phys_obj;
- int ret;
-
- if (dev_priv->mm.phys_objs[id - 1] || !size)
- return 0;
-
- phys_obj = kzalloc(sizeof(*phys_obj), GFP_KERNEL);
- if (!phys_obj)
- return -ENOMEM;
-
- phys_obj->id = id;
-
- phys_obj->handle = drm_pci_alloc(dev, size, align);
- if (!phys_obj->handle) {
- ret = -ENOMEM;
- goto kfree_obj;
- }
-#ifdef CONFIG_X86
- set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
-#endif
-
- dev_priv->mm.phys_objs[id - 1] = phys_obj;
-
- return 0;
-kfree_obj:
- kfree(phys_obj);
- return ret;
-}
-
-static void i915_gem_free_phys_object(struct drm_device *dev, int id)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_phys_object *phys_obj;
-
- if (!dev_priv->mm.phys_objs[id - 1])
- return;
-
- phys_obj = dev_priv->mm.phys_objs[id - 1];
- if (phys_obj->cur_obj) {
- i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
- }
-
-#ifdef CONFIG_X86
- set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
-#endif
- drm_pci_free(dev, phys_obj->handle);
- kfree(phys_obj);
- dev_priv->mm.phys_objs[id - 1] = NULL;
-}
-
-void i915_gem_free_all_phys_object(struct drm_device *dev)
-{
- int i;
-
- for (i = I915_GEM_PHYS_CURSOR_0; i <= I915_MAX_PHYS_OBJECT; i++)
- i915_gem_free_phys_object(dev, i);
-}
-
-void i915_gem_detach_phys_object(struct drm_device *dev,
- struct drm_i915_gem_object *obj)
-{
- struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
- char *vaddr;
- int i;
- int page_count;
-
- if (!obj->phys_obj)
- return;
- vaddr = obj->phys_obj->handle->vaddr;
-
- page_count = obj->base.size / PAGE_SIZE;
- for (i = 0; i < page_count; i++) {
- struct page *page = shmem_read_mapping_page(mapping, i);
- if (!IS_ERR(page)) {
- char *dst = kmap_atomic(page);
- memcpy(dst, vaddr + i*PAGE_SIZE, PAGE_SIZE);
- kunmap_atomic(dst);
-
- drm_clflush_pages(&page, 1);
-
- set_page_dirty(page);
- mark_page_accessed(page);
- page_cache_release(page);
- }
- }
- i915_gem_chipset_flush(dev);
-
- obj->phys_obj->cur_obj = NULL;
- obj->phys_obj = NULL;
-}
-
-int
-i915_gem_attach_phys_object(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- int id,
- int align)
-{
- struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret = 0;
- int page_count;
- int i;
-
- if (id > I915_MAX_PHYS_OBJECT)
- return -EINVAL;
-
- if (obj->phys_obj) {
- if (obj->phys_obj->id == id)
- return 0;
- i915_gem_detach_phys_object(dev, obj);
- }
-
- /* create a new object */
- if (!dev_priv->mm.phys_objs[id - 1]) {
- ret = i915_gem_init_phys_object(dev, id,
- obj->base.size, align);
- if (ret) {
- DRM_ERROR("failed to init phys object %d size: %zu\n",
- id, obj->base.size);
- return ret;
- }
- }
-
- /* bind to the object */
- obj->phys_obj = dev_priv->mm.phys_objs[id - 1];
- obj->phys_obj->cur_obj = obj;
-
- page_count = obj->base.size / PAGE_SIZE;
-
- for (i = 0; i < page_count; i++) {
- struct page *page;
- char *dst, *src;
-
- page = shmem_read_mapping_page(mapping, i);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- src = kmap_atomic(page);
- dst = obj->phys_obj->handle->vaddr + (i * PAGE_SIZE);
- memcpy(dst, src, PAGE_SIZE);
- kunmap_atomic(src);
-
- mark_page_accessed(page);
- page_cache_release(page);
- }
-
- return 0;
-}
-
-static int
-i915_gem_phys_pwrite(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pwrite *args,
- struct drm_file *file_priv)
-{
- void *vaddr = obj->phys_obj->handle->vaddr + args->offset;
- char __user *user_data = to_user_ptr(args->data_ptr);
-
- if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
- unsigned long unwritten;
-
- /* The physical object once assigned is fixed for the lifetime
- * of the obj, so we can safely drop the lock and continue
- * to access vaddr.
- */
- mutex_unlock(&dev->struct_mutex);
- unwritten = copy_from_user(vaddr, user_data, args->size);
- mutex_lock(&dev->struct_mutex);
- if (unwritten)
- return -EFAULT;
- }
-
- i915_gem_chipset_flush(dev);
- return 0;
-}
-
void i915_gem_release(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
bool intel_enable_ppgtt(struct drm_device *dev, bool full)
{
- if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
+ if (i915.enable_ppgtt == 0)
return false;
if (i915.enable_ppgtt == 1 && full)
return false;
+ return true;
+}
+
+static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
+{
+ if (enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
+ return 0;
+
+ if (enable_ppgtt == 1)
+ return 1;
+
+ if (enable_ppgtt == 2 && HAS_PPGTT(dev))
+ return 2;
+
#ifdef CONFIG_INTEL_IOMMU
/* Disable ppgtt on SNB if VT-d is on. */
if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {
DRM_INFO("Disabling PPGTT because VT-d is on\n");
- return false;
+ return 0;
}
#endif
- /* Full ppgtt disabled by default for now due to issues. */
- if (full)
- return HAS_PPGTT(dev) && (i915.enable_ppgtt == 2);
- else
- return HAS_ALIASING_PPGTT(dev);
+ return HAS_ALIASING_PPGTT(dev) ? 1 : 0;
}
if (ret == -ENOSPC && !retried) {
ret = i915_gem_evict_something(dev, &dev_priv->gtt.base,
GEN6_PD_SIZE, GEN6_PD_ALIGN,
- I915_CACHE_NONE, 0);
+ I915_CACHE_NONE,
+ 0, dev_priv->gtt.base.total,
+ 0);
if (ret)
return ret;
bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
if (bdw_gmch_ctl)
bdw_gmch_ctl = 1 << bdw_gmch_ctl;
+
+ #ifdef CONFIG_X86_32
+ /* Limit 32b platforms to a 2GB GGTT: 4 << 20 / pte size * PAGE_SIZE */
+ if (bdw_gmch_ctl > 4)
+ bdw_gmch_ctl = 4;
+ #endif
+
return bdw_gmch_ctl << 20;
}
if (intel_iommu_gfx_mapped)
DRM_INFO("VT-d active for gfx access\n");
#endif
+ /*
+ * i915.enable_ppgtt is read-only, so do an early pass to validate the
+ * user's requested state against the hardware/driver capabilities. We
+ * do this now so that we can print out any log messages once rather
+ * than every time we check intel_enable_ppgtt().
+ */
+ i915.enable_ppgtt = sanitize_enable_ppgtt(dev, i915.enable_ppgtt);
+ DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915.enable_ppgtt);
return 0;
}
dev_priv->vbt.edp_pps = *edp_pps;
- dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
- DP_LINK_BW_1_62;
+ switch (edp_link_params->rate) {
+ case EDP_RATE_1_62:
+ dev_priv->vbt.edp_rate = DP_LINK_BW_1_62;
+ break;
+ case EDP_RATE_2_7:
+ dev_priv->vbt.edp_rate = DP_LINK_BW_2_7;
+ break;
+ default:
+ DRM_DEBUG_KMS("VBT has unknown eDP link rate value %u\n",
+ edp_link_params->rate);
+ break;
+ }
+
switch (edp_link_params->lanes) {
- case 0:
+ case EDP_LANE_1:
dev_priv->vbt.edp_lanes = 1;
break;
- case 1:
+ case EDP_LANE_2:
dev_priv->vbt.edp_lanes = 2;
break;
- case 3:
- default:
+ case EDP_LANE_4:
dev_priv->vbt.edp_lanes = 4;
break;
+ default:
+ DRM_DEBUG_KMS("VBT has unknown eDP lane count value %u\n",
+ edp_link_params->lanes);
+ break;
}
+
switch (edp_link_params->preemphasis) {
- case 0:
+ case EDP_PREEMPHASIS_NONE:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
break;
- case 1:
+ case EDP_PREEMPHASIS_3_5dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
break;
- case 2:
+ case EDP_PREEMPHASIS_6dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
break;
- case 3:
+ case EDP_PREEMPHASIS_9_5dB:
dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
break;
+ default:
+ DRM_DEBUG_KMS("VBT has unknown eDP pre-emphasis value %u\n",
+ edp_link_params->preemphasis);
+ break;
}
+
switch (edp_link_params->vswing) {
- case 0:
+ case EDP_VSWING_0_4V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400;
break;
- case 1:
+ case EDP_VSWING_0_6V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600;
break;
- case 2:
+ case EDP_VSWING_0_8V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800;
break;
- case 3:
+ case EDP_VSWING_1_2V:
dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200;
break;
+ default:
+ DRM_DEBUG_KMS("VBT has unknown eDP voltage swing value %u\n",
+ edp_link_params->vswing);
+ break;
}
}
int i, panel_id, seq_size;
u16 block_size;
+ /* parse MIPI blocks only if LFP type is MIPI */
+ if (!dev_priv->vbt.has_mipi)
+ return;
+
/* Initialize this to undefined indicating no generic MIPI support */
dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
/* skip the device block if device type is invalid */
continue;
}
+
+ if (p_child->common.dvo_port >= DVO_PORT_MIPIA
+ && p_child->common.dvo_port <= DVO_PORT_MIPID
+ &&p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT) {
+ DRM_DEBUG_KMS("Found MIPI as LFP\n");
+ dev_priv->vbt.has_mipi = 1;
+ dev_priv->vbt.dsi.port = p_child->common.dvo_port;
+ }
+
child_dev_ptr = dev_priv->vbt.child_dev + count;
count++;
memcpy((void *)child_dev_ptr, (void *)p_child,
if (!IS_VALLEYVIEW(dev))
return;
- /*
- * Enable the CRI clock source so we can get at the display and the
- * reference clock for VGA hotplug / manual detection.
- */
- I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
- DPLL_REFA_CLK_ENABLE_VLV |
- DPLL_INTEGRATED_CRI_CLK_VLV);
-
if (IS_CHERRYVIEW(dev)) {
enum dpio_phy phy;
u32 val;
} else {
/*
- * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
- * 6. De-assert cmn_reset/side_reset. Same as VLV X0.
- * a. GUnit 0x2110 bit[0] set to 1 (def 0)
- * b. The other bits such as sfr settings / modesel may all
- * be set to 0.
- *
- * This should only be done on init and resume from S3 with
- * both PLLs disabled, or we risk losing DPIO and PLL
- * synchronization.
+ * If DPIO has already been reset, e.g. by BIOS, just skip all
+ * this.
*/
- I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST);
+ if (I915_READ(DPIO_CTL) & DPIO_CMNRST)
+ return;
+
+ /*
+ * From VLV2A0_DP_eDP_HDMI_DPIO_driver_vbios_notes_11.docx:
+ * Need to assert and de-assert PHY SB reset by gating the
+ * common lane power, then un-gating it.
+ * Simply ungating isn't enough to reset the PHY enough to get
+ * ports and lanes running.
+ */
+ __vlv_set_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC,
+ false);
+ __vlv_set_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC,
+ true);
}
}
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- bool visible = base != 0;
- u32 cntl;
+ uint32_t cntl;
- if (intel_crtc->cursor_visible == visible)
- return;
-
- cntl = I915_READ(_CURACNTR);
- if (visible) {
+ if (base != intel_crtc->cursor_base) {
/* On these chipsets we can only modify the base whilst
* the cursor is disabled.
*/
+ if (intel_crtc->cursor_cntl) {
+ I915_WRITE(_CURACNTR, 0);
+ POSTING_READ(_CURACNTR);
+ intel_crtc->cursor_cntl = 0;
+ }
+
I915_WRITE(_CURABASE, base);
+ POSTING_READ(_CURABASE);
+ }
- cntl &= ~(CURSOR_FORMAT_MASK);
- /* XXX width must be 64, stride 256 => 0x00 << 28 */
- cntl |= CURSOR_ENABLE |
+ /* XXX width must be 64, stride 256 => 0x00 << 28 */
+ cntl = 0;
+ if (base)
+ cntl = (CURSOR_ENABLE |
CURSOR_GAMMA_ENABLE |
- CURSOR_FORMAT_ARGB;
- } else
- cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
- I915_WRITE(_CURACNTR, cntl);
-
- intel_crtc->cursor_visible = visible;
+ CURSOR_FORMAT_ARGB);
+ if (intel_crtc->cursor_cntl != cntl) {
+ I915_WRITE(_CURACNTR, cntl);
+ POSTING_READ(_CURACNTR);
+ intel_crtc->cursor_cntl = cntl;
+ }
}
static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- 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 |= MCURSOR_GAMMA_ENABLE;
+ uint32_t cntl;
- switch (width) {
+ cntl = 0;
+ if (base) {
+ cntl = MCURSOR_GAMMA_ENABLE;
+ switch (intel_crtc->cursor_width) {
case 64:
cntl |= CURSOR_MODE_64_ARGB_AX;
break;
default:
WARN_ON(1);
return;
- }
- cntl |= pipe << 28; /* Connect to correct pipe */
- } else {
- cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
- cntl |= CURSOR_MODE_DISABLE;
}
+ cntl |= pipe << 28; /* Connect to correct pipe */
+ }
+ if (intel_crtc->cursor_cntl != cntl) {
I915_WRITE(CURCNTR(pipe), cntl);
-
- intel_crtc->cursor_visible = visible;
+ POSTING_READ(CURCNTR(pipe));
+ intel_crtc->cursor_cntl = cntl;
}
+
/* and commit changes on next vblank */
- POSTING_READ(CURCNTR(pipe));
I915_WRITE(CURBASE(pipe), base);
POSTING_READ(CURBASE(pipe));
}
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- 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;
- cntl |= MCURSOR_GAMMA_ENABLE;
- switch (width) {
+ uint32_t cntl;
+
+ cntl = 0;
+ if (base) {
+ cntl = MCURSOR_GAMMA_ENABLE;
+ switch (intel_crtc->cursor_width) {
case 64:
cntl |= CURSOR_MODE_64_ARGB_AX;
break;
default:
WARN_ON(1);
return;
- }
- } else {
- cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
- cntl |= CURSOR_MODE_DISABLE;
}
- if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
- cntl |= CURSOR_PIPE_CSC_ENABLE;
- cntl &= ~CURSOR_TRICKLE_FEED_DISABLE;
- }
- I915_WRITE(CURCNTR(pipe), cntl);
+ }
+ if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+ cntl |= CURSOR_PIPE_CSC_ENABLE;
- intel_crtc->cursor_visible = visible;
+ if (intel_crtc->cursor_cntl != cntl) {
+ I915_WRITE(CURCNTR(pipe), cntl);
+ POSTING_READ(CURCNTR(pipe));
+ intel_crtc->cursor_cntl = cntl;
}
+
/* and commit changes on next vblank */
- POSTING_READ(CURCNTR(pipe));
I915_WRITE(CURBASE(pipe), base);
POSTING_READ(CURBASE(pipe));
}
int x = intel_crtc->cursor_x;
int y = intel_crtc->cursor_y;
u32 base = 0, pos = 0;
- bool visible;
if (on)
base = intel_crtc->cursor_addr;
}
pos |= y << CURSOR_Y_SHIFT;
- visible = base != 0;
- if (!visible && !intel_crtc->cursor_visible)
+ if (base == 0 && intel_crtc->cursor_base == 0)
return;
I915_WRITE(CURPOS(pipe), pos);
i845_update_cursor(crtc, base);
else
i9xx_update_cursor(crtc, base);
+ intel_crtc->cursor_base = base;
}
static int intel_crtc_cursor_set(struct drm_crtc *crtc,
addr = i915_gem_obj_ggtt_offset(obj);
} else {
int align = IS_I830(dev) ? 16 * 1024 : 256;
- ret = i915_gem_attach_phys_object(dev, obj,
- (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1,
- align);
+ ret = i915_gem_object_attach_phys(obj, align);
if (ret) {
DRM_DEBUG_KMS("failed to attach phys object\n");
goto fail_locked;
}
- addr = obj->phys_obj->handle->busaddr;
+ addr = obj->phys_handle->busaddr;
}
if (IS_GEN2(dev))
finish:
if (intel_crtc->cursor_bo) {
- if (INTEL_INFO(dev)->cursor_needs_physical) {
- if (intel_crtc->cursor_bo != obj)
- i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
- } else
+ if (!INTEL_INFO(dev)->cursor_needs_physical)
i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo);
drm_gem_object_unreference(&intel_crtc->cursor_bo->base);
}
intel_crtc->plane = !pipe;
}
+ intel_crtc->cursor_base = ~0;
+ intel_crtc->cursor_cntl = ~0;
+
init_waitqueue_head(&intel_crtc->vbl_wait);
BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
intel_lvds_init(dev);
- if (!IS_ULT(dev) && !IS_CHERRYVIEW(dev))
+ if (!IS_ULT(dev) && !IS_CHERRYVIEW(dev) && dev_priv->vbt.int_crt_support)
intel_crt_init(dev);
if (HAS_DDI(dev)) {
/* ThinkPad T60 needs pipe A force quirk (bug #16494) */
{ 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
- /* 830 needs to leave pipe A & dpll A up */
- { 0x3577, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
-
/* Lenovo U160 cannot use SSC on LVDS */
{ 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable },
}
}
-static void
-intel_connector_break_all_links(struct intel_connector *connector)
-{
- connector->base.dpms = DRM_MODE_DPMS_OFF;
- connector->base.encoder = NULL;
- connector->encoder->connectors_active = false;
- connector->encoder->base.crtc = NULL;
-}
-
static void intel_enable_pipe_a(struct drm_device *dev)
{
struct intel_connector *connector;
if (connector->encoder->base.crtc != &crtc->base)
continue;
- intel_connector_break_all_links(connector);
+ connector->base.dpms = DRM_MODE_DPMS_OFF;
+ connector->base.encoder = NULL;
}
+ /* multiple connectors may have the same encoder:
+ * handle them and break crtc link separately */
+ list_for_each_entry(connector, &dev->mode_config.connector_list,
+ base.head)
+ if (connector->encoder->base.crtc == &crtc->base) {
+ connector->encoder->base.crtc = NULL;
+ connector->encoder->connectors_active = false;
+ }
WARN_ON(crtc->active);
crtc->base.enabled = false;
encoder->base.name);
encoder->disable(encoder);
}
+ encoder->base.crtc = NULL;
+ encoder->connectors_active = false;
/* Inconsistent output/port/pipe state happens presumably due to
* a bug in one of the get_hw_state functions. Or someplace else
base.head) {
if (connector->encoder != encoder)
continue;
-
- intel_connector_break_all_links(connector);
+ connector->base.dpms = DRM_MODE_DPMS_OFF;
+ connector->base.encoder = NULL;
}
}
/* Enabled encoders without active connectors will be fixed in
}
}
+static bool ilk_increase_wm_latency(struct drm_i915_private *dev_priv,
+ uint16_t wm[5], uint16_t min)
+{
+ int level, max_level = ilk_wm_max_level(dev_priv->dev);
+
+ if (wm[0] >= min)
+ return false;
+
+ wm[0] = max(wm[0], min);
+ for (level = 1; level <= max_level; level++)
+ wm[level] = max_t(uint16_t, wm[level], DIV_ROUND_UP(min, 5));
+
+ return true;
+}
+
+static void snb_wm_latency_quirk(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ bool changed;
+
+ /*
+ * The BIOS provided WM memory latency values are often
+ * inadequate for high resolution displays. Adjust them.
+ */
+ changed = ilk_increase_wm_latency(dev_priv, dev_priv->wm.pri_latency, 12) |
+ ilk_increase_wm_latency(dev_priv, dev_priv->wm.spr_latency, 12) |
+ ilk_increase_wm_latency(dev_priv, dev_priv->wm.cur_latency, 12);
+
+ if (!changed)
+ return;
+
+ DRM_DEBUG_KMS("WM latency values increased to avoid potential underruns\n");
+ intel_print_wm_latency(dev, "Primary", dev_priv->wm.pri_latency);
+ intel_print_wm_latency(dev, "Sprite", dev_priv->wm.spr_latency);
+ intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);
+}
+
static void ilk_setup_wm_latency(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
intel_print_wm_latency(dev, "Primary", dev_priv->wm.pri_latency);
intel_print_wm_latency(dev, "Sprite", dev_priv->wm.spr_latency);
intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);
+
+ if (IS_GEN6(dev))
+ snb_wm_latency_quirk(dev);
}
static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
I915_WRITE(GEN6_UCGCTL2,
GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
- /* WaDisableL3Bank2xClockGate:vlv */
- I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
+ /* WaDisableL3Bank2xClockGate:vlv
+ * Disabling L3 clock gating- MMIO 940c[25] = 1
+ * Set bit 25, to disable L3_BANK_2x_CLK_GATING */
+ I915_WRITE(GEN7_UCGCTL4,
+ I915_READ(GEN7_UCGCTL4) | GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
/* IIR "flip pending" means done if this bit is set */
I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE));
+
+ /* interrupts should cause a wake up from C3 */
+ I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_INT_EN));
+
+ /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
+ I915_WRITE(MI_ARB_STATE, _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
}
static void i85x_init_clock_gating(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+
+ /* interrupts should cause a wake up from C3 */
+ I915_WRITE(MI_STATE, _MASKED_BIT_ENABLE(MI_AGPBUSY_INT_EN) |
+ _MASKED_BIT_DISABLE(MI_AGPBUSY_830_MODE));
}
static void i830_init_clock_gating(struct drm_device *dev)
enum intel_display_power_domain domain)
{
struct i915_power_domains *power_domains;
+ struct i915_power_well *power_well;
+ bool is_enabled;
+ int i;
+
+ if (dev_priv->pm.suspended)
+ return false;
power_domains = &dev_priv->power_domains;
+ is_enabled = true;
+ for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
+ if (power_well->always_on)
+ continue;
- return power_domains->domain_use_count[domain];
+ if (!power_well->count) {
+ is_enabled = false;
+ break;
+ }
+ }
+ return is_enabled;
}
bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
return true;
}
- static void vlv_set_power_well(struct drm_i915_private *dev_priv,
- struct i915_power_well *power_well, bool enable)
+ void __vlv_set_power_well(struct drm_i915_private *dev_priv,
+ enum punit_power_well power_well_id, bool enable)
{
- enum punit_power_well power_well_id = power_well->data;
+ struct drm_device *dev = dev_priv->dev;
u32 mask;
u32 state;
u32 ctrl;
+ enum pipe pipe;
+
+ if (power_well_id == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ if (enable) {
+ /*
+ * Enable the CRI clock source so we can get at the
+ * display and the reference clock for VGA
+ * hotplug / manual detection.
+ */
+ I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
+ DPLL_REFA_CLK_ENABLE_VLV |
+ DPLL_INTEGRATED_CRI_CLK_VLV);
+ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
+ } else {
+ for_each_pipe(pipe)
+ assert_pll_disabled(dev_priv, pipe);
+ /* Assert common reset */
+ I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) &
+ ~DPIO_CMNRST);
+ }
+ }
mask = PUNIT_PWRGT_MASK(power_well_id);
state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
out:
mutex_unlock(&dev_priv->rps.hw_lock);
+
+ /*
+ * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
+ * 6. De-assert cmn_reset/side_reset. Same as VLV X0.
+ * a. GUnit 0x2110 bit[0] set to 1 (def 0)
+ * b. The other bits such as sfr settings / modesel may all
+ * be set to 0.
+ *
+ * This should only be done on init and resume from S3 with
+ * both PLLs disabled, or we risk losing DPIO and PLL
+ * synchronization.
+ */
+ if (power_well_id == PUNIT_POWER_WELL_DPIO_CMN_BC && enable)
+ I915_WRITE(DPIO_CTL, I915_READ(DPIO_CTL) | DPIO_CMNRST);
+ }
+
+ static void vlv_set_power_well(struct drm_i915_private *dev_priv,
+ struct i915_power_well *power_well, bool enable)
+ {
+ enum punit_power_well power_well_id = power_well->data;
+
+ __vlv_set_power_well(dev_priv, power_well_id, enable);
}
static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
.data = PUNIT_POWER_WELL_DISP2D,
.ops = &vlv_display_power_well_ops,
},
- {
- .name = "dpio-common",
- .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
- .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
- .ops = &vlv_dpio_power_well_ops,
- },
{
.name = "dpio-tx-b-01",
.domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
.ops = &vlv_dpio_power_well_ops,
.data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
},
+ {
+ .name = "dpio-common",
+ .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
+ .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
+ .ops = &vlv_dpio_power_well_ops,
+ },
};
#define set_power_wells(power_domains, __power_wells) ({ \
{
__raw_i915_write32(dev_priv, FORCEWAKE_VLV,
_MASKED_BIT_DISABLE(0xffff));
+ __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
+ _MASKED_BIT_DISABLE(0xffff));
/* something from same cacheline, but !FORCEWAKE_VLV */
__raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
}
void intel_uncore_sanitize(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg_val;
-
/* BIOS often leaves RC6 enabled, but disable it for hw init */
intel_disable_gt_powersave(dev);
-
- /* Turn off power gate, require especially for the BIOS less system */
- if (IS_VALLEYVIEW(dev)) {
-
- mutex_lock(&dev_priv->rps.hw_lock);
- reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS);
-
- if (reg_val & (PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_RENDER) |
- PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_MEDIA) |
- PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_DISP2D)))
- vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, 0x0);
-
- mutex_unlock(&dev_priv->rps.hw_lock);
-
- }
}
/*
{
int ret;
+ /* FIXME: i965g/gm need a display save/restore for gpu reset. */
+ return -ENODEV;
+
/*
* Set the domains we want to reset (GRDOM/bits 2 and 3) as
* well as the reset bit (GR/bit 0). Setting the GR bit