From 304eb30a10bb37d55ed781cb9bfffe3e850f46a5 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Fri, 22 Nov 2013 14:45:09 +0000 Subject: [PATCH] i915: enable tiled framebuffer git-svn-id: svn://kolibrios.org@4280 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/video/drm/drm_gem.c | 7 - drivers/video/drm/i915/Makefile | 1 + drivers/video/drm/i915/i915_dma.c | 4 +- drivers/video/drm/i915/i915_drv.c | 8 +- drivers/video/drm/i915/i915_drv.h | 40 +++-- drivers/video/drm/i915/i915_gem.c | 7 +- drivers/video/drm/i915/i915_gem_context.c | 24 ++- drivers/video/drm/i915/i915_gem_gtt.c | 116 +++++++++---- drivers/video/drm/i915/i915_reg.h | 6 + drivers/video/drm/i915/intel_crt.c | 26 ++- drivers/video/drm/i915/intel_ddi.c | 19 +- drivers/video/drm/i915/intel_display.c | 203 ++++++++++++++-------- drivers/video/drm/i915/intel_dp.c | 20 +++ drivers/video/drm/i915/intel_drv.h | 2 + drivers/video/drm/i915/intel_fb.c | 44 ++--- drivers/video/drm/i915/intel_lvds.c | 16 ++ drivers/video/drm/i915/intel_pm.c | 4 +- drivers/video/drm/i915/kms_display.c | 80 +++++++-- drivers/video/drm/i915/kos_gem_fb.c | 199 +++++++++++++++++++++ drivers/video/drm/i915/main.c | 197 +++++++++++++++++---- drivers/video/drm/i915/pci.c | 13 +- 21 files changed, 805 insertions(+), 231 deletions(-) create mode 100644 drivers/video/drm/i915/kos_gem_fb.c diff --git a/drivers/video/drm/drm_gem.c b/drivers/video/drm/drm_gem.c index 78264fcf1f..02c0c9dc1d 100644 --- a/drivers/video/drm/drm_gem.c +++ b/drivers/video/drm/drm_gem.c @@ -273,7 +273,6 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle) idr_remove(&filp->object_idr, handle); spin_unlock(&filp->table_lock); -// drm_gem_remove_prime_handles(obj, filp); if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, filp); @@ -317,12 +316,6 @@ drm_gem_handle_create_tail(struct drm_file *file_priv, } *handlep = ret; -// ret = drm_vma_node_allow(&obj->vma_node, file_priv->filp); -// if (ret) { -// drm_gem_handle_delete(file_priv, *handlep); -// return ret; -// } - if (dev->driver->gem_open_object) { ret = dev->driver->gem_open_object(obj, file_priv); if (ret) { diff --git a/drivers/video/drm/i915/Makefile b/drivers/video/drm/i915/Makefile index 5c22b0ffc0..412a528c10 100644 --- a/drivers/video/drm/i915/Makefile +++ b/drivers/video/drm/i915/Makefile @@ -76,6 +76,7 @@ NAME_SRC= main.c \ intel_sprite.c \ intel_uncore.c \ kms_display.c \ + kos_gem_fb.c \ utils.c \ ../hdmi.c \ Gtt/intel-agp.c \ diff --git a/drivers/video/drm/i915/i915_dma.c b/drivers/video/drm/i915/i915_dma.c index b5f7e323a5..a06ee27bce 100644 --- a/drivers/video/drm/i915/i915_dma.c +++ b/drivers/video/drm/i915/i915_dma.c @@ -1156,7 +1156,7 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) DRM_INFO("failed to find VBIOS tables\n"); - + fb_obj = kos_gem_fb_object_create(dev,0,12*1024*1024); /* Initialise stolen first so that we may reserve preallocated * objects for the BIOS to KMS transition. @@ -1524,6 +1524,8 @@ 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); diff --git a/drivers/video/drm/i915/i915_drv.c b/drivers/video/drm/i915/i915_drv.c index df3f662fa6..32c4152827 100644 --- a/drivers/video/drm/i915/i915_drv.c +++ b/drivers/video/drm/i915/i915_drv.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(panel_ignore_lid, "Override lid status (0=autodetect, 1=autodetect disabled [default], " "-1=force lid closed, -2=force lid open)"); -unsigned int i915_powersave __read_mostly = 1; +unsigned int i915_powersave __read_mostly = 0; module_param_named(powersave, i915_powersave, int, 0600); MODULE_PARM_DESC(powersave, "Enable powersavings, fbc, downclocking, etc. (default: true)"); @@ -72,7 +72,7 @@ module_param_named(semaphores, i915_semaphores, int, 0600); MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))"); -int i915_enable_rc6 __read_mostly = -1; +int i915_enable_rc6 __read_mostly = 0; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400); MODULE_PARM_DESC(i915_enable_rc6, "Enable power-saving render C-state 6. " @@ -81,7 +81,7 @@ MODULE_PARM_DESC(i915_enable_rc6, "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " "default: -1 (use per-chip default)"); -int i915_enable_fbc __read_mostly = -1; +int i915_enable_fbc __read_mostly = 0; module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); MODULE_PARM_DESC(i915_enable_fbc, "Enable frame buffer compression for power savings " @@ -150,7 +150,7 @@ module_param_named(fastboot, i915_fastboot, bool, 0600); MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time " "(default: false)"); -int i915_enable_pc8 __read_mostly = 1; +int i915_enable_pc8 __read_mostly = 0; 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)"); diff --git a/drivers/video/drm/i915/i915_drv.h b/drivers/video/drm/i915/i915_drv.h index f66356a960..ed6bdc9562 100644 --- a/drivers/video/drm/i915/i915_drv.h +++ b/drivers/video/drm/i915/i915_drv.h @@ -509,10 +509,12 @@ struct i915_address_space { /* FIXME: Need a more generic return type */ gen6_gtt_pte_t (*pte_encode)(dma_addr_t addr, - enum i915_cache_level level); + enum i915_cache_level level, + bool valid); /* Create a valid PTE */ void (*clear_range)(struct i915_address_space *vm, unsigned int first_entry, - unsigned int num_entries); + unsigned int num_entries, + bool use_scratch); void (*insert_entries)(struct i915_address_space *vm, struct sg_table *st, unsigned int first_entry, @@ -2071,6 +2073,8 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj); +void i915_check_and_clear_faults(struct drm_device *dev); +void i915_gem_suspend_gtt_mappings(struct drm_device *dev); void i915_gem_restore_gtt_mappings(struct drm_device *dev); int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, @@ -2340,6 +2344,12 @@ timespec_to_jiffies_timeout(const struct timespec *value) return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1); } +static inline int mutex_trylock(struct mutex *lock) +{ + if (likely(atomic_cmpxchg(&lock->count, 1, 0) == 1)) + return 1; + return 0; +} typedef struct { @@ -2349,19 +2359,27 @@ typedef struct int freq; }videomode_t; - -static inline int mutex_trylock(struct mutex *lock) +struct cmdtable { - if (likely(atomic_cmpxchg(&lock->count, 1, 0) == 1)) - return 1; - return 0; -} + char *key; + int size; + int *val; +}; + +#define CMDENTRY(key, val) {(key), (sizeof(key)-1), &val} + +void parse_cmdline(char *cmdline, struct cmdtable *table, char *log, videomode_t *mode); +struct drm_i915_gem_object +*kos_gem_fb_object_create(struct drm_device *dev, u32 gtt_offset, u32 size); + +extern struct drm_i915_gem_object *fb_obj; +static struct drm_i915_gem_object *get_fb_obj() +{ + return fb_obj; +}; #define ioread32(addr) readl(addr) - - - #endif diff --git a/drivers/video/drm/i915/i915_gem.c b/drivers/video/drm/i915/i915_gem.c index 090db4d74e..991e70060c 100644 --- a/drivers/video/drm/i915/i915_gem.c +++ b/drivers/video/drm/i915/i915_gem.c @@ -26,6 +26,7 @@ */ #include +#include #include #include "i915_drv.h" #include "i915_trace.h" @@ -2619,6 +2620,9 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, POSTING_READ(fence_reg + 4); I915_WRITE(fence_reg + 0, val); + + dbgprintf("%s val %x%x\n",__FUNCTION__, (int)(val >> 32), (int)val); + POSTING_READ(fence_reg); } else { I915_WRITE(fence_reg + 4, 0); @@ -3668,9 +3672,6 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT)) return -EBUSY; -// if( obj == get_fb_obj()) -// return 0; - WARN_ON(map_and_fenceable && !i915_is_ggtt(vm)); vma = i915_gem_obj_to_vma(obj, vm); diff --git a/drivers/video/drm/i915/i915_gem_context.c b/drivers/video/drm/i915/i915_gem_context.c index 97533b3130..403309c2a7 100644 --- a/drivers/video/drm/i915/i915_gem_context.c +++ b/drivers/video/drm/i915/i915_gem_context.c @@ -299,11 +299,31 @@ static int context_idr_cleanup(int id, void *p, void *data) BUG_ON(id == DEFAULT_CONTEXT_ID); - - + i915_gem_context_unreference(ctx); return 0; } +struct i915_ctx_hang_stats * +i915_gem_context_get_hang_stats(struct drm_device *dev, + struct drm_file *file, + u32 id) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_file_private *file_priv = file->driver_priv; + struct i915_hw_context *ctx; + + if (id == DEFAULT_CONTEXT_ID) + return &file_priv->hang_stats; + + ctx = NULL; + if (!dev_priv->hw_contexts_disabled) + ctx = i915_gem_context_get(file->driver_priv, id); + if (ctx == NULL) + return ERR_PTR(-ENOENT); + + return &ctx->hang_stats; +} + void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; diff --git a/drivers/video/drm/i915/i915_gem_gtt.c b/drivers/video/drm/i915/i915_gem_gtt.c index aaf3836415..9cc75121b7 100644 --- a/drivers/video/drm/i915/i915_gem_gtt.c +++ b/drivers/video/drm/i915/i915_gem_gtt.c @@ -65,9 +65,10 @@ #define HSW_WT_ELLC_LLC_AGE0 HSW_CACHEABILITY_CONTROL(0x6) static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + bool valid) { - gen6_gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0; pte |= GEN6_PTE_ADDR_ENCODE(addr); switch (level) { @@ -86,9 +87,10 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr, } static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + bool valid) { - gen6_gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0; pte |= GEN6_PTE_ADDR_ENCODE(addr); switch (level) { @@ -112,9 +114,10 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr, #define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2) static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + bool valid) { - gen6_gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0; pte |= GEN6_PTE_ADDR_ENCODE(addr); /* Mark the page as writeable. Other platforms don't have a @@ -129,9 +132,10 @@ static gen6_gtt_pte_t byt_pte_encode(dma_addr_t addr, } static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + bool valid) { - gen6_gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0; pte |= HSW_PTE_ADDR_ENCODE(addr); if (level != I915_CACHE_NONE) @@ -141,9 +145,10 @@ static gen6_gtt_pte_t hsw_pte_encode(dma_addr_t addr, } static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr, - enum i915_cache_level level) + enum i915_cache_level level, + bool valid) { - gen6_gtt_pte_t pte = GEN6_PTE_VALID; + gen6_gtt_pte_t pte = valid ? GEN6_PTE_VALID : 0; pte |= HSW_PTE_ADDR_ENCODE(addr); switch (level) { @@ -243,7 +248,8 @@ static int gen6_ppgtt_enable(struct drm_device *dev) /* PPGTT support for Sandybdrige/Gen6 and later */ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, unsigned first_entry, - unsigned num_entries) + unsigned num_entries, + bool use_scratch) { struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); @@ -252,7 +258,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC); + scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); pt_vaddr = AllocKernelSpace(4096); @@ -301,7 +307,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, dma_addr_t page_addr; page_addr = sg_page_iter_dma_address(&sg_iter); - pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level); + pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level, true); if (++act_pte == I915_PPGTT_PT_ENTRIES) { act_pt++; MapPage(pt_vaddr,(addr_t)(ppgtt->pt_pages[act_pt]), 3); @@ -380,7 +386,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) } ppgtt->base.clear_range(&ppgtt->base, 0, - ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); + ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true); ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t); @@ -457,7 +463,8 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, { ppgtt->base.clear_range(&ppgtt->base, i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); + obj->base.size >> PAGE_SHIFT, + true); } extern int intel_iommu_gfx_mapped; @@ -498,15 +505,65 @@ static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) dev_priv->mm.interruptible = interruptible; } +void i915_check_and_clear_faults(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *ring; + int i; + + if (INTEL_INFO(dev)->gen < 6) + return; + + for_each_ring(ring, dev_priv, i) { + u32 fault_reg; + fault_reg = I915_READ(RING_FAULT_REG(ring)); + if (fault_reg & RING_FAULT_VALID) { + DRM_DEBUG_DRIVER("Unexpected fault\n" + "\tAddr: 0x%08lx\\n" + "\tAddress space: %s\n" + "\tSource ID: %d\n" + "\tType: %d\n", + fault_reg & PAGE_MASK, + fault_reg & RING_FAULT_GTTSEL_MASK ? "GGTT" : "PPGTT", + RING_FAULT_SRCID(fault_reg), + RING_FAULT_FAULT_TYPE(fault_reg)); + I915_WRITE(RING_FAULT_REG(ring), + fault_reg & ~RING_FAULT_VALID); + } + } + POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS])); +} + +void i915_gem_suspend_gtt_mappings(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Don't bother messing with faults pre GEN6 as we have little + * documentation supporting that it's a good idea. + */ + if (INTEL_INFO(dev)->gen < 6) + return; + + i915_check_and_clear_faults(dev); + + dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, + dev_priv->gtt.base.start / PAGE_SIZE, + dev_priv->gtt.base.total / PAGE_SIZE, + false); +} + void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; + i915_check_and_clear_faults(dev); + /* First fill our portion of the GTT with scratch pages */ dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, dev_priv->gtt.base.start / PAGE_SIZE, - dev_priv->gtt.base.total / PAGE_SIZE); + dev_priv->gtt.base.total / PAGE_SIZE, + true); list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { i915_gem_clflush_object(obj, obj->pin_display); @@ -549,7 +606,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm, for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) { addr = sg_page_iter_dma_address(&sg_iter); - iowrite32(vm->pte_encode(addr, level), >t_entries[i]); + iowrite32(vm->pte_encode(addr, level, true), >t_entries[i]); i++; } @@ -561,7 +618,7 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm, */ if (i != 0) WARN_ON(readl(>t_entries[i-1]) != - vm->pte_encode(addr, level)); + vm->pte_encode(addr, level, true)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -573,7 +630,8 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm, static void gen6_ggtt_clear_range(struct i915_address_space *vm, unsigned int first_entry, - unsigned int num_entries) + unsigned int num_entries, + bool use_scratch) { struct drm_i915_private *dev_priv = vm->dev->dev_private; gen6_gtt_pte_t scratch_pte, __iomem *gtt_base = @@ -586,7 +644,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC); + scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch); + for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); readl(gtt_base); @@ -607,7 +666,8 @@ static void i915_ggtt_insert_entries(struct i915_address_space *vm, static void i915_ggtt_clear_range(struct i915_address_space *vm, unsigned int first_entry, - unsigned int num_entries) + unsigned int num_entries, + bool unused) { intel_gtt_clear_range(first_entry, num_entries); } @@ -635,7 +695,8 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) dev_priv->gtt.base.clear_range(&dev_priv->gtt.base, entry, - obj->base.size >> PAGE_SHIFT); + obj->base.size >> PAGE_SHIFT, + true); obj->has_global_gtt_mapping = 0; } @@ -722,11 +783,11 @@ void i915_gem_setup_global_gtt(struct drm_device *dev, const unsigned long count = (hole_end - hole_start) / PAGE_SIZE; DRM_DEBUG_KMS("clearing unused GTT space: [%lx, %lx]\n", hole_start, hole_end); - ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count); + ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count, true); } /* And finally clear the reserved guard page */ - ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1); + ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true); } static bool @@ -752,7 +813,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev) gtt_size = dev_priv->gtt.base.total; mappable_size = dev_priv->gtt.mappable_end; -#if 0 if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { int ret; @@ -762,7 +822,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) gtt_size -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE; } - i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size-LFB_SIZE); + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); ret = i915_gem_init_aliasing_ppgtt(dev); if (!ret) @@ -772,9 +832,7 @@ void i915_gem_init_global_gtt(struct drm_device *dev) drm_mm_takedown(&dev_priv->gtt.base.mm); gtt_size += GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE; } -#endif - - i915_gem_setup_global_gtt(dev, LFB_SIZE, mappable_size, gtt_size-LFB_SIZE); + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } static int setup_scratch_page(struct drm_device *dev) diff --git a/drivers/video/drm/i915/i915_reg.h b/drivers/video/drm/i915/i915_reg.h index 463a32da42..ceead33312 100644 --- a/drivers/video/drm/i915/i915_reg.h +++ b/drivers/video/drm/i915/i915_reg.h @@ -604,6 +604,10 @@ #define ARB_MODE_SWIZZLE_IVB (1<<5) #define RENDER_HWS_PGA_GEN7 (0x04080) #define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id) +#define RING_FAULT_GTTSEL_MASK (1<<11) +#define RING_FAULT_SRCID(x) ((x >> 3) & 0xff) +#define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3) +#define RING_FAULT_VALID (1<<0) #define DONE_REG 0x40b0 #define BSD_HWS_PGA_GEN7 (0x04180) #define BLT_HWS_PGA_GEN7 (0x04280) @@ -4279,7 +4283,9 @@ #define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) #define SOUTH_DSPCLK_GATE_D 0xc2020 +#define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30) #define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) +#define PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14) #define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12) /* CPU: FDI_TX */ diff --git a/drivers/video/drm/i915/intel_crt.c b/drivers/video/drm/i915/intel_crt.c index 854e3c2b7a..edc5508565 100644 --- a/drivers/video/drm/i915/intel_crt.c +++ b/drivers/video/drm/i915/intel_crt.c @@ -82,8 +82,7 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder, return true; } -static void intel_crt_get_config(struct intel_encoder *encoder, - struct intel_crtc_config *pipe_config) +static unsigned int intel_crt_get_flags(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_crt *crt = intel_encoder_to_crt(encoder); @@ -101,7 +100,25 @@ static void intel_crt_get_config(struct intel_encoder *encoder, else flags |= DRM_MODE_FLAG_NVSYNC; - pipe_config->adjusted_mode.flags |= flags; + return flags; +} + +static void intel_crt_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder); +} + +static void hsw_crt_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config) +{ + intel_ddi_get_config(encoder, pipe_config); + + pipe_config->adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC | + DRM_MODE_FLAG_NHSYNC | + DRM_MODE_FLAG_PVSYNC | + DRM_MODE_FLAG_NVSYNC); + pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder); } /* Note: The caller is required to filter out dpms modes not supported by the @@ -776,6 +793,9 @@ void intel_crt_init(struct drm_device *dev) crt->base.mode_set = intel_crt_mode_set; crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; + if (IS_HASWELL(dev)) + crt->base.get_config = hsw_crt_get_config; + else crt->base.get_config = intel_crt_get_config; if (I915_HAS_HOTPLUG(dev)) crt->base.hpd_pin = HPD_CRT; diff --git a/drivers/video/drm/i915/intel_ddi.c b/drivers/video/drm/i915/intel_ddi.c index 54b6b8e850..d168cdb77e 100644 --- a/drivers/video/drm/i915/intel_ddi.c +++ b/drivers/video/drm/i915/intel_ddi.c @@ -1249,7 +1249,7 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) intel_dp_check_link_status(intel_dp); } -static void intel_ddi_get_config(struct intel_encoder *encoder, +void intel_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; @@ -1268,6 +1268,23 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, flags |= DRM_MODE_FLAG_NVSYNC; pipe_config->adjusted_mode.flags |= flags; + + switch (temp & TRANS_DDI_BPC_MASK) { + case TRANS_DDI_BPC_6: + pipe_config->pipe_bpp = 18; + break; + case TRANS_DDI_BPC_8: + pipe_config->pipe_bpp = 24; + break; + case TRANS_DDI_BPC_10: + pipe_config->pipe_bpp = 30; + break; + case TRANS_DDI_BPC_12: + pipe_config->pipe_bpp = 36; + break; + default: + break; + } } static void intel_ddi_destroy(struct drm_encoder *encoder) diff --git a/drivers/video/drm/i915/intel_display.c b/drivers/video/drm/i915/intel_display.c index b5e6e423de..e3b668dadb 100644 --- a/drivers/video/drm/i915/intel_display.c +++ b/drivers/video/drm/i915/intel_display.c @@ -1828,6 +1828,8 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, u32 alignment; int ret; + ENTER(); + switch (obj->tiling_mode) { case I915_TILING_NONE: if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) @@ -1876,6 +1878,9 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, i915_gem_object_pin_fence(obj); dev_priv->mm.interruptible = true; + + LEAVE(); + return 0; err_unpin: @@ -2240,15 +2245,28 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } mutex_lock(&dev->struct_mutex); -// ret = intel_pin_and_fence_fb_obj(dev, -// to_intel_framebuffer(fb)->obj, -// NULL); -// if (ret != 0) { -// mutex_unlock(&dev->struct_mutex); -// DRM_ERROR("pin & fence failed\n"); -// return ret; -// } + ret = intel_pin_and_fence_fb_obj(dev, + to_intel_framebuffer(fb)->obj, + NULL); + if (ret != 0) { + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("pin & fence failed\n"); + return ret; + } + /* Update pipe size and adjust fitter if needed */ + if (i915_fastboot) { + I915_WRITE(PIPESRC(intel_crtc->pipe), + ((crtc->mode.hdisplay - 1) << 16) | + (crtc->mode.vdisplay - 1)); + if (!intel_crtc->config.pch_pfit.enabled && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { + I915_WRITE(PF_CTL(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0); + I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0); + } + } ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { @@ -2317,9 +2335,10 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } -static bool pipe_has_enabled_pch(struct intel_crtc *intel_crtc) +static bool pipe_has_enabled_pch(struct intel_crtc *crtc) { - return intel_crtc->base.enabled && intel_crtc->config.has_pch_encoder; + return crtc->base.enabled && crtc->active && + crtc->config.has_pch_encoder; } static void ivb_modeset_global_resources(struct drm_device *dev) @@ -2971,6 +2990,48 @@ static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc, I915_READ(VSYNCSHIFT(cpu_transcoder))); } +static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t temp; + + temp = I915_READ(SOUTH_CHICKEN1); + if (temp & FDI_BC_BIFURCATION_SELECT) + return; + + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); + WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); + + temp |= FDI_BC_BIFURCATION_SELECT; + DRM_DEBUG_KMS("enabling fdi C rx\n"); + I915_WRITE(SOUTH_CHICKEN1, temp); + POSTING_READ(SOUTH_CHICKEN1); +} + +static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + switch (intel_crtc->pipe) { + case PIPE_A: + break; + case PIPE_B: + if (intel_crtc->config.fdi_lanes > 2) + WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); + else + cpt_enable_fdi_bc_bifurcation(dev); + + break; + case PIPE_C: + cpt_enable_fdi_bc_bifurcation(dev); + + break; + default: + BUG(); + } +} + /* * Enable PCH resources required for PCH ports: * - PCH PLLs @@ -2989,6 +3050,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) assert_pch_transcoder_disabled(dev_priv, pipe); + if (IS_IVYBRIDGE(dev)) + ivybridge_update_fdi_bc_bifurcation(intel_crtc); + /* Write the TU size bits before fdi link training, so that error * detection works. */ I915_WRITE(FDI_RX_TUSIZE1(pipe), @@ -3852,12 +3916,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc) assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); -// if (crtc->fb) { -// mutex_lock(&dev->struct_mutex); -// intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); -// mutex_unlock(&dev->struct_mutex); -// crtc->fb = NULL; -// } + if (crtc->fb) { + mutex_lock(&dev->struct_mutex); + intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); + mutex_unlock(&dev->struct_mutex); + crtc->fb = NULL; + } /* Update computed state. */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -4977,6 +5041,22 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc, if (!(tmp & PIPECONF_ENABLE)) return false; + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + switch (tmp & PIPECONF_BPC_MASK) { + case PIPECONF_6BPC: + pipe_config->pipe_bpp = 18; + break; + case PIPECONF_8BPC: + pipe_config->pipe_bpp = 24; + break; + case PIPECONF_10BPC: + pipe_config->pipe_bpp = 30; + break; + default: + break; + } + } + intel_get_pipe_timings(crtc, pipe_config); i9xx_get_pfit_config(crtc, pipe_config); @@ -5570,48 +5650,6 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, return true; } -static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t temp; - - temp = I915_READ(SOUTH_CHICKEN1); - if (temp & FDI_BC_BIFURCATION_SELECT) - return; - - WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE); - WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE); - - temp |= FDI_BC_BIFURCATION_SELECT; - DRM_DEBUG_KMS("enabling fdi C rx\n"); - I915_WRITE(SOUTH_CHICKEN1, temp); - POSTING_READ(SOUTH_CHICKEN1); -} - -static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) -{ - struct drm_device *dev = intel_crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - switch (intel_crtc->pipe) { - case PIPE_A: - break; - case PIPE_B: - if (intel_crtc->config.fdi_lanes > 2) - WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT); - else - cpt_enable_fdi_bc_bifurcation(dev); - - break; - case PIPE_C: - cpt_enable_fdi_bc_bifurcation(dev); - - break; - default: - BUG(); - } -} - int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp) { /* @@ -5805,9 +5843,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, &intel_crtc->config.fdi_m_n); } - if (IS_IVYBRIDGE(dev)) - ivybridge_update_fdi_bc_bifurcation(intel_crtc); - ironlake_set_pipeconf(crtc); /* Set up the display plane register */ @@ -5875,6 +5910,23 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc, if (!(tmp & PIPECONF_ENABLE)) return false; + switch (tmp & PIPECONF_BPC_MASK) { + case PIPECONF_6BPC: + pipe_config->pipe_bpp = 18; + break; + case PIPECONF_8BPC: + pipe_config->pipe_bpp = 24; + break; + case PIPECONF_10BPC: + pipe_config->pipe_bpp = 30; + break; + case PIPECONF_12BPC: + pipe_config->pipe_bpp = 36; + break; + default: + break; + } + if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) { struct intel_shared_dpll *pll; @@ -7050,22 +7102,22 @@ mode_fits_in_fbdev(struct drm_device *dev, struct drm_i915_gem_object *obj; struct drm_framebuffer *fb; -// if (dev_priv->fbdev == NULL) -// return NULL; - -// obj = dev_priv->fbdev->ifb.obj; -// if (obj == NULL) + if (dev_priv->fbdev == NULL) return NULL; -// if (obj->base.size < mode->vdisplay * fb->pitch) + obj = dev_priv->fbdev->ifb.obj; + if (obj == NULL) + return NULL; + + fb = &dev_priv->fbdev->ifb.base; if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay, fb->bits_per_pixel)) -// return NULL; + return NULL; if (obj->base.size < mode->vdisplay * fb->pitches[0]) return NULL; -// return fb; + return fb; } bool intel_get_load_detect_pipe(struct drm_connector *connector, @@ -8597,6 +8649,9 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_X(dpll_hw_state.fp0); PIPE_CONF_CHECK_X(dpll_hw_state.fp1); + if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) + PIPE_CONF_CHECK_I(pipe_bpp); + #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_FLAGS @@ -9952,10 +10007,6 @@ static void intel_init_quirks(struct drm_device *dev) q->subsystem_device == PCI_ANY_ID)) q->hook(dev); } -// for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) { -// if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0) -// intel_dmi_quirks[i].hook(dev); -// } } /* Disable the VGA plane that we never use */ @@ -10471,11 +10522,9 @@ void intel_modeset_cleanup(struct drm_device *dev) /* flush any delayed tasks or pending work */ flush_scheduled_work(); -// cancel_work_sync(&dev_priv->hotplug_work); -// cancel_work_sync(&dev_priv->rps.work); - /* flush any delayed tasks or pending work */ -// flush_scheduled_work(); + /* destroy backlight, if any, before the connectors */ + intel_panel_destroy_backlight(dev); drm_mode_config_cleanup(dev); #endif diff --git a/drivers/video/drm/i915/intel_dp.c b/drivers/video/drm/i915/intel_dp.c index 1d9e938cfb..ddcb22dfd7 100644 --- a/drivers/video/drm/i915/intel_dp.c +++ b/drivers/video/drm/i915/intel_dp.c @@ -1390,6 +1390,26 @@ static void intel_dp_get_config(struct intel_encoder *encoder, else pipe_config->port_clock = 270000; } + + if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp && + pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) { + /* + * This is a big fat ugly hack. + * + * Some machines in UEFI boot mode provide us a VBT that has 18 + * bpp and 1.62 GHz link bandwidth for eDP, which for reasons + * unknown we fail to light up. Yet the same BIOS boots up with + * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as + * max, not what it tells us to use. + * + * Note: This will still be broken if the eDP panel is not lit + * up by the BIOS, and thus we can't get the mode at module + * load. + */ + DRM_DEBUG_KMS("pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", + pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp); + dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp; + } } static bool is_edp_psr(struct intel_dp *intel_dp) diff --git a/drivers/video/drm/i915/intel_drv.h b/drivers/video/drm/i915/intel_drv.h index 25c35c1e89..95c92864d4 100644 --- a/drivers/video/drm/i915/intel_drv.h +++ b/drivers/video/drm/i915/intel_drv.h @@ -770,6 +770,8 @@ extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); extern bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); extern void intel_ddi_fdi_disable(struct drm_crtc *crtc); +extern void intel_ddi_get_config(struct intel_encoder *encoder, + struct intel_crtc_config *pipe_config); extern void intel_display_handle_reset(struct drm_device *dev); extern bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev, diff --git a/drivers/video/drm/i915/intel_fb.c b/drivers/video/drm/i915/intel_fb.c index d5d1f33db2..b69074fa47 100644 --- a/drivers/video/drm/i915/intel_fb.c +++ b/drivers/video/drm/i915/intel_fb.c @@ -43,12 +43,7 @@ #include #include "i915_drv.h" -static struct drm_i915_gem_object *fb_obj; - -struct drm_i915_gem_object *get_fb_obj() -{ - return fb_obj; -}; +struct drm_i915_gem_object *fb_obj; struct fb_info *framebuffer_alloc(size_t size, struct device *dev) { @@ -105,6 +100,8 @@ static int intelfb_create(struct drm_fb_helper *helper, struct device *device = &dev->pdev->dev; int size, ret; + ENTER(); + /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) sizes->surface_bpp = 32; @@ -113,49 +110,29 @@ static int intelfb_create(struct drm_fb_helper *helper, mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / - 8), 64); + 8), 512); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); size = mode_cmd.pitches[0] * mode_cmd.height; size = ALIGN(size, PAGE_SIZE); - obj = i915_gem_alloc_object(dev, size); + obj = fb_obj; if (!obj) { DRM_ERROR("failed to allocate framebuffer\n"); ret = -ENOMEM; goto out; } + obj->stride = mode_cmd.pitches[0]; + mutex_lock(&dev->struct_mutex); -#if 0 -// skip this part and use existing framebiffer - /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, false); + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; } -#endif - -/***********************************************************************/ - { -#define LFB_SIZE 0xC00000 - - static struct drm_mm_node lfb_vm_node; - - lfb_vm_node.size = LFB_SIZE; - lfb_vm_node.start = 0; - lfb_vm_node.mm = NULL; - - obj->pin_count = 2; - obj->cache_level = I915_CACHE_NONE; - obj->base.write_domain = 0; - obj->base.read_domains = I915_GEM_DOMAIN_GTT; - - } -/***********************************************************************/ info = framebuffer_alloc(0, device); if (!info) { @@ -194,6 +171,8 @@ static int intelfb_create(struct drm_fb_helper *helper, info->screen_base = (void*) 0xFE000000; info->screen_size = size; + /* This driver doesn't need a VT switch to restore the mode on resume */ + info->skip_vt_switch = true; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); @@ -206,9 +185,6 @@ static int intelfb_create(struct drm_fb_helper *helper, mutex_unlock(&dev->struct_mutex); - - fb_obj = obj; - return 0; out_unpin: diff --git a/drivers/video/drm/i915/intel_lvds.c b/drivers/video/drm/i915/intel_lvds.c index e482cd94c0..69df8b1192 100644 --- a/drivers/video/drm/i915/intel_lvds.c +++ b/drivers/video/drm/i915/intel_lvds.c @@ -698,6 +698,22 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Intel D410PT", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel"), + DMI_MATCH(DMI_BOARD_NAME, "D410PT"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Intel D425KT", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "D425KT"), + }, + }, { .callback = intel_no_lvds_dmi_callback, .ident = "Intel D510MO", diff --git a/drivers/video/drm/i915/intel_pm.c b/drivers/video/drm/i915/intel_pm.c index 90d8626d88..34eb1c2a32 100644 --- a/drivers/video/drm/i915/intel_pm.c +++ b/drivers/video/drm/i915/intel_pm.c @@ -4768,7 +4768,9 @@ static void cpt_init_clock_gating(struct drm_device *dev) * gating for the panel power sequencer or it will fail to * start up when no ports are active. */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE | + PCH_DPLUNIT_CLOCK_GATE_DISABLE | + PCH_CPUNIT_CLOCK_GATE_DISABLE); I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | DPLS_EDP_PPS_FIX_DIS); /* The below fixes the weird display corruption, a few pixels shifted diff --git a/drivers/video/drm/i915/kms_display.c b/drivers/video/drm/i915/kms_display.c index 2c189bacb3..2691edfae7 100644 --- a/drivers/video/drm/i915/kms_display.c +++ b/drivers/video/drm/i915/kms_display.c @@ -106,6 +106,7 @@ bool set_mode(struct drm_device *dev, struct drm_connector *connector, struct drm_framebuffer *fb = NULL; struct drm_crtc *crtc; struct drm_encoder *encoder; + struct drm_i915_gem_object *fb_obj; struct drm_mode_set set; char *con_name; char *enc_name; @@ -162,14 +163,16 @@ do_set: if (crtc->invert_dimensions) swap(hdisplay, vdisplay); + fb_obj = get_fb_obj(); fb = fb_helper->fb; fb->width = reqmode->width; fb->height = reqmode->height; - fb->pitches[0] = ALIGN(reqmode->width * 4, 64); - fb->pitches[1] = ALIGN(reqmode->width * 4, 64); - fb->pitches[2] = ALIGN(reqmode->width * 4, 64); - fb->pitches[3] = ALIGN(reqmode->width * 4, 64); + + fb->pitches[0] = fb->pitches[1] = fb->pitches[2] = + fb->pitches[3] = ALIGN(reqmode->width * 4, 512); + + fb_obj->stride = fb->pitches[0]; fb->bits_per_pixel = 32; fb->depth = 24; @@ -178,6 +181,8 @@ do_set: crtc->enabled = true; os_display->crtc = crtc; + i915_gem_object_put_fence(fb_obj); + set.crtc = crtc; set.x = 0; set.y = 0; @@ -261,7 +266,7 @@ static struct drm_connector* get_def_connector(struct drm_device *dev) }; -int init_display_kms(struct drm_device *dev) +int init_display_kms(struct drm_device *dev, videomode_t *usermode) { struct drm_connector *connector; struct drm_connector_helper_funcs *connector_funcs; @@ -273,6 +278,10 @@ int init_display_kms(struct drm_device *dev) u32_t ifl; int err; + ENTER(); + + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if( connector->status != connector_status_connected) @@ -289,20 +298,22 @@ int init_display_kms(struct drm_device *dev) connector->encoder = encoder; crtc = encoder->crtc; - DRM_DEBUG_KMS("CONNECTOR %x ID:%d status:%d ENCODER %x CRTC %x ID:%d\n", + DRM_DEBUG_KMS("CONNECTOR %p ID:%d status:%d ENCODER %x CRTC %p ID:%d\n", connector, connector->base.id, connector->status, connector->encoder, crtc, crtc->base.id ); - break; }; if(connector == NULL) { - DRM_ERROR("No active connectors!\n"); + DRM_DEBUG_KMS("No active connectors!\n"); + mutex_unlock(&dev->mode_config.mutex); return -1; }; + dbgprintf("CRTC %p\n", crtc); + if(crtc == NULL) { struct drm_crtc *tmp_crtc; @@ -310,24 +321,28 @@ int init_display_kms(struct drm_device *dev) list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { + dbgprintf("tmp_crtc %p\n", tmp_crtc); if (encoder->possible_crtcs & crtc_mask) { crtc = tmp_crtc; encoder->crtc = crtc; + dbgprintf("CRTC %p\n", crtc); break; }; crtc_mask <<= 1; }; }; + dbgprintf("CRTC %p\n", crtc); + if(crtc == NULL) { - DRM_ERROR("No CRTC for encoder %d\n", encoder->base.id); + DRM_DEBUG_KMS("No CRTC for encoder %d\n", encoder->base.id); + mutex_unlock(&dev->mode_config.mutex); return -1; }; - - DRM_DEBUG_KMS("[Select CRTC:%d]\n", crtc->base.id); + DRM_DEBUG_KMS("[Select CRTC: %p ID:%d]\n",crtc, crtc->base.id); os_display = GetDisplay(); os_display->ddev = dev; @@ -361,10 +376,53 @@ int init_display_kms(struct drm_device *dev) }; safe_sti(ifl); + if( (usermode->width == 0) || + (usermode->height == 0)) + { + struct drm_display_mode *mode; + +// connector->funcs->fill_modes(connector, dev->mode_config.max_width, +// dev->mode_config.max_height); + + list_for_each_entry(mode, &connector->modes, head) + { + printf("check mode w:%d h:%d %dHz\n", + drm_mode_width(mode), drm_mode_height(mode), + drm_mode_vrefresh(mode)); + + if( os_display->width == drm_mode_width(mode) && + os_display->height == drm_mode_height(mode) && + drm_mode_vrefresh(mode) == 60) + { + usermode->width = os_display->width; + usermode->height = os_display->height; + usermode->freq = 60; + break; + + } + } + + if( usermode->width == 0 || + usermode->height == 0) + { + mode = list_entry(connector->modes.next, typeof(*mode), head); + + usermode->width = drm_mode_width(mode); + usermode->height = drm_mode_height(mode); + usermode->freq = drm_mode_vrefresh(mode); + }; + }; + + mutex_unlock(&dev->mode_config.mutex); + + set_mode(dev, os_display->connector, usermode, false); + #ifdef __HWA__ err = init_bitmaps(); #endif + LEAVE(); + return 0; }; diff --git a/drivers/video/drm/i915/kos_gem_fb.c b/drivers/video/drm/i915/kos_gem_fb.c new file mode 100644 index 0000000000..01cb7470b0 --- /dev/null +++ b/drivers/video/drm/i915/kos_gem_fb.c @@ -0,0 +1,199 @@ +/* + * Copyright © 2008-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include +#include +#include "i915_drv.h" + +static struct sg_table * +i915_pages_create_for_fb(struct drm_device *dev, + u32 offset, u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sg_table *st; + struct scatterlist *sg; + addr_t fb_pages; + + DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size); +// BUG_ON(offset > dev_priv->gtt.stolen_size - size); + + /* We hide that we have no struct page backing our stolen object + * by wrapping the contiguous physical allocation with a fake + * dma mapping in a single scatterlist. + */ + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) + return NULL; + + if (sg_alloc_table(st, 1, GFP_KERNEL)) { + kfree(st); + return NULL; + } + + fb_pages = AllocPages(size/PAGE_SIZE); + if(fb_pages == 0) + { + kfree(st); + return NULL; + }; + + sg = st->sgl; + sg->offset = offset; + sg->length = size; + + sg_dma_address(sg) = (dma_addr_t)fb_pages; + sg_dma_len(sg) = size; + + return st; +} + + +static int kos_fb_object_get_pages(struct drm_i915_gem_object *obj) +{ + BUG(); + return -EINVAL; +} + +static void kos_fb_object_put_pages(struct drm_i915_gem_object *obj) +{ + /* Should only be called during free */ + sg_free_table(obj->pages); + kfree(obj->pages); +} + +static const struct drm_i915_gem_object_ops kos_fb_object_ops = { + .get_pages = kos_fb_object_get_pages, + .put_pages = kos_fb_object_put_pages, +}; + +static struct drm_i915_gem_object * +_kos_fb_object_create(struct drm_device *dev, + struct drm_mm_node *fb_node) +{ + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_alloc(dev); + if (obj == NULL) + return NULL; + + drm_gem_private_object_init(dev, &obj->base, fb_node->size); + i915_gem_object_init(obj, &kos_fb_object_ops); + + obj->pages = i915_pages_create_for_fb(dev, + fb_node->start, fb_node->size); + if (obj->pages == NULL) + goto cleanup; + + obj->has_dma_mapping = true; + i915_gem_object_pin_pages(obj); + obj->stolen = fb_node; + + obj->base.read_domains = I915_GEM_DOMAIN_GTT; + obj->cache_level = I915_CACHE_NONE; + obj->tiling_mode = I915_TILING_X; + + return obj; + +cleanup: + i915_gem_object_free(obj); + return NULL; +} + + +struct drm_i915_gem_object * +kos_gem_fb_object_create(struct drm_device *dev, + u32 gtt_offset, + u32 size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_address_space *ggtt = &dev_priv->gtt.base; + struct drm_i915_gem_object *obj; + struct drm_mm_node *fb_node; + struct i915_vma *vma; + int ret; + + DRM_DEBUG_KMS("creating preallocated framebuffer object: gtt_offset=%x, size=%x\n", + gtt_offset, size); + + /* KISS and expect everything to be page-aligned */ + BUG_ON(size & 4095); + + if (WARN_ON(size == 0)) + return NULL; + + fb_node = kzalloc(sizeof(*fb_node), GFP_KERNEL); + if (!fb_node) + return NULL; + + fb_node->start = gtt_offset; + fb_node->size = size; + + obj = _kos_fb_object_create(dev, fb_node); + if (obj == NULL) { + DRM_DEBUG_KMS("failed to preallocate framebuffer object\n"); + kfree(fb_node); + return NULL; + } + + vma = i915_gem_vma_create(obj, ggtt); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto err_out; + } + + /* To simplify the initialisation sequence between KMS and GTT, + * we allow construction of the stolen object prior to + * setting up the GTT space. The actual reservation will occur + * later. + */ + vma->node.start = gtt_offset; + vma->node.size = size; + if (drm_mm_initialized(&ggtt->mm)) { + ret = drm_mm_reserve_node(&ggtt->mm, &vma->node); + if (ret) { + DRM_DEBUG_KMS("failed to allocate framebuffer GTT space\n"); + goto err_vma; + } + } + + obj->has_global_gtt_mapping = 1; + + list_add_tail(&obj->global_list, &dev_priv->mm.bound_list); + list_add_tail(&vma->mm_list, &ggtt->inactive_list); + + return obj; + +err_vma: + i915_gem_vma_destroy(vma); +err_out: + kfree(fb_node); + drm_gem_object_unreference(&obj->base); + return NULL; +} + diff --git a/drivers/video/drm/i915/main.c b/drivers/video/drm/i915/main.c index 22609f1aac..32d92d1390 100644 --- a/drivers/video/drm/i915/main.c +++ b/drivers/video/drm/i915/main.c @@ -28,10 +28,10 @@ struct pci_device { struct drm_device *main_device; struct drm_file *drm_file_handlers[256]; +videomode_t usermode; void cpu_detect(); -void parse_cmdline(char *cmdline, char *log); int _stdcall display_handler(ioctl_t *io); int init_agp(void); @@ -51,6 +51,15 @@ int i915_getparam(struct drm_device *dev, void *data, int i915_mask_update(struct drm_device *dev, void *data, struct drm_file *file); +struct cmdtable cmdtable[]= { + CMDENTRY("-pm=", i915_powersave), + CMDENTRY("-rc6=", i915_enable_rc6), + CMDENTRY("-fbc=", i915_enable_fbc), + CMDENTRY("-ppgt=", i915_enable_ppgtt), + CMDENTRY("-pc8=", i915_enable_pc8), + {NULL, 0} +}; + static char log[256]; @@ -158,8 +167,22 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) if( GetService("DISPLAY") != 0 ) return 0; + printf("i915 v3.12\n\nusage: i915 [options]\n" + "-pm=<0,1> Enable powersavings, fbc, downclocking, etc. (default: 0 - false)\n"); + printf("-rc6=<-1,0-7> Enable power-saving render C-state 6.\n" + " Different stages can be selected via bitmask values\n" + " (0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6).\n" + " For example, 3 would enable rc6 and deep rc6, and 7 would enable everything.\n" + " default: -1 (use per-chip default)\n"); + printf("-fbc=<-1,0,1> Enable frame buffer compression for power savings\n" + " (default: 0 - false)\n"); + printf("-ppgt=<0,1> Enable PPGTT (default: 0 - false)\n"); + printf("-pc8=<0,1> Enable support for low power package C states (PC8+) (default: 0 - false)\n"); + printf("-l path to log file\n"); + printf("-m set videomode\n"); + if( cmdline && *cmdline ) - parse_cmdline(cmdline, log); + parse_cmdline(cmdline, cmdtable, log, &usermode); if(!dbg_open(log)) { @@ -171,7 +194,6 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) return 0; }; } - dbgprintf(" i915 v3.12-6\n cmdline: %s\n", cmdline); cpu_detect(); // dbgprintf("\ncache line size %d\n", x86_clflush_size); @@ -184,7 +206,8 @@ u32_t __attribute__((externally_visible)) drvEntry(int action, char *cmdline) dbgprintf("Epic Fail :(\n"); return 0; }; - init_display_kms(main_device); + + init_display_kms(main_device, &usermode); err = RegService("DISPLAY", display_handler); @@ -458,38 +481,6 @@ int pci_scan_filter(u32_t id, u32_t busnr, u32_t devfn) }; -static char* parse_path(char *p, char *log) -{ - char c; - - while( (c = *p++) == ' '); - p--; - while( (c = *log++ = *p++) && (c != ' ')); - *log = 0; - - return p; -}; - -void parse_cmdline(char *cmdline, char *log) -{ - char *p = cmdline; - - char c = *p++; - - while( c ) - { - if( c == '-') - { - switch(*p++) - { - case 'l': - p = parse_path(p, log); - break; - }; - }; - c = *p++; - }; -}; static inline void __cpuid(unsigned int *eax, unsigned int *ebx, @@ -571,3 +562,137 @@ void get_pci_info(struct pci_device *dev) +char *strstr(const char *cs, const char *ct); + +static int my_atoi(char **cmd) +{ + char* p = *cmd; + int val = 0; + int sign = 1; + + if(*p == '-') + { + sign = -1; + p++; + }; + + for (;; *p++) { + switch (*p) { + case '0' ... '9': + val = 10*val+(*p-'0'); + break; + default: + *cmd = p; + return val*sign; + } + } +} + +char* parse_mode(char *p, videomode_t *mode) +{ + char c; + + while( (c = *p++) == ' '); + + if( c ) + { + p--; + + mode->width = my_atoi(&p); + if(*p == 'x') p++; + + mode->height = my_atoi(&p); + if(*p == 'x') p++; + + mode->bpp = 32; + + mode->freq = my_atoi(&p); + + if( mode->freq == 0 ) + mode->freq = 60; + } + + return p; +}; + + +static char* parse_path(char *p, char *log) +{ + char c; + + while( (c = *p++) == ' '); + p--; + while( (c = *log++ = *p++) && (c != ' ')); + *log = 0; + + return p; +}; + +void parse_cmdline(char *cmdline, struct cmdtable *table, char *log, videomode_t *mode) +{ + char *p = cmdline; + char *p1; + int val; + char c = *p++; + + if( table ) + { + while(table->key) + { + if(p1 = strstr(cmdline, table->key)) + { + p1+= table->size; + *table->val = my_atoi(&p1); +// printf("%s %d\n", table->key, *table->val); + } + table++; + } + } + + while( c ) + { + if( c == '-') + { + switch(*p++) + { + case 'l': + p = parse_path(p, log); + break; + + case 'm': + p = parse_mode(p, mode); + break; + }; + }; + c = *p++; + }; +}; + +char *strstr(const char *cs, const char *ct) +{ +int d0, d1; +register char *__res; +__asm__ __volatile__( + "movl %6,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %6,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + : "=a" (__res), "=&c" (d0), "=&S" (d1) + : "0" (0), "1" (0xffffffff), "2" (cs), "g" (ct) + : "dx", "di"); +return __res; +} diff --git a/drivers/video/drm/i915/pci.c b/drivers/video/drm/i915/pci.c index 70bf33fbbd..accd6024f0 100644 --- a/drivers/video/drm/i915/pci.c +++ b/drivers/video/drm/i915/pci.c @@ -783,18 +783,9 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) return (void __iomem *)(unsigned long) pci_resource_start(pdev, PCI_ROM_RESOURCE); } else { - /* assign the ROM an address if it doesn't have one */ -// if (res->parent == NULL && -// pci_assign_resource(pdev,PCI_ROM_RESOURCE)) - return NULL; -// start = pci_resource_start(pdev, PCI_ROM_RESOURCE); -// *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); -// if (*size == 0) -// return NULL; + start = (loff_t)0xC0000; + *size = 0x20000; /* cover C000:0 through E000:0 */ - /* Enable ROM space decodes */ -// if (pci_enable_rom(pdev)) -// return NULL; } }