diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 112 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 239 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_debugfs.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 219 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 190 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_mem.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_opregion.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 616 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_suspend.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_bios.c | 92 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_bios.h | 101 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 76 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 665 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_hdmi.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 151 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 110 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_tv.c | 14 |
19 files changed, 2440 insertions, 318 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 0ccb63ee50e..f112c769d53 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -33,6 +33,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#define I915_DRV "i915_drv" + /* Really want an OS-independent resettable timer. Would like to have * this loop run for (eg) 3 sec, but have the timer reset every time * the head pointer changes, so that EBUSY only happens if the ring @@ -99,7 +101,7 @@ static int i915_init_phys_hws(struct drm_device *dev) memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); + DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n"); return 0; } @@ -185,7 +187,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) master_priv->sarea_priv = (drm_i915_sarea_t *) ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset); } else { - DRM_DEBUG("sarea not found assuming DRI2 userspace\n"); + DRM_DEBUG_DRIVER(I915_DRV, + "sarea not found assuming DRI2 userspace\n"); } if (init->ring_size != 0) { @@ -235,7 +238,7 @@ static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - DRM_DEBUG("%s\n", __func__); + DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__); if (dev_priv->ring.map.handle == NULL) { DRM_ERROR("can not ioremap virtual address for" @@ -248,13 +251,14 @@ static int i915_dma_resume(struct drm_device * dev) DRM_ERROR("Can not find hardware status page\n"); return -EINVAL; } - DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); + DRM_DEBUG_DRIVER(I915_DRV, "hw status page @ %p\n", + dev_priv->hw_status_page); if (dev_priv->status_gfx_addr != 0) I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); else I915_WRITE(HWS_PGA, dev_priv->dma_status_page); - DRM_DEBUG("Enabled hardware status page\n"); + DRM_DEBUG_DRIVER(I915_DRV, "Enabled hardware status page\n"); return 0; } @@ -548,10 +552,10 @@ static int i915_dispatch_flip(struct drm_device * dev) if (!master_priv->sarea_priv) return -EINVAL; - DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", - __func__, - dev_priv->current_page, - master_priv->sarea_priv->pf_current_page); + DRM_DEBUG_DRIVER(I915_DRV, "%s: page=%d pfCurrentPage=%d\n", + __func__, + dev_priv->current_page, + master_priv->sarea_priv->pf_current_page); i915_kernel_lost_context(dev); @@ -629,8 +633,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, return -EINVAL; } - DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", - batch->start, batch->used, batch->num_cliprects); + DRM_DEBUG_DRIVER(I915_DRV, + "i915 batchbuffer, start %x used %d cliprects %d\n", + batch->start, batch->used, batch->num_cliprects); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -638,9 +643,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, return -EINVAL; if (batch->num_cliprects) { - cliprects = drm_calloc(batch->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(batch->num_cliprects, + sizeof(struct drm_clip_rect), + GFP_KERNEL); if (cliprects == NULL) return -ENOMEM; @@ -659,9 +664,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_free: - drm_free(cliprects, - batch->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -678,15 +681,16 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, void *batch_data; int ret; - DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n", - cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); + DRM_DEBUG_DRIVER(I915_DRV, + "i915 cmdbuffer, buf %p sz %d cliprects %d\n", + cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); if (cmdbuf->num_cliprects < 0) return -EINVAL; - batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER); + batch_data = kmalloc(cmdbuf->sz, GFP_KERNEL); if (batch_data == NULL) return -ENOMEM; @@ -695,9 +699,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, goto fail_batch_free; if (cmdbuf->num_cliprects) { - cliprects = drm_calloc(cmdbuf->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(cmdbuf->num_cliprects, + sizeof(struct drm_clip_rect), GFP_KERNEL); if (cliprects == NULL) goto fail_batch_free; @@ -720,11 +723,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_clip_free: - drm_free(cliprects, - cmdbuf->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); fail_batch_free: - drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER); + kfree(batch_data); return ret; } @@ -734,7 +735,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, { int ret; - DRM_DEBUG("%s\n", __func__); + DRM_DEBUG_DRIVER(I915_DRV, "%s\n", __func__); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -777,7 +778,8 @@ static int i915_getparam(struct drm_device *dev, void *data, value = dev_priv->num_fence_regs - dev_priv->fence_reg_start; break; default: - DRM_DEBUG("Unknown parameter %d\n", param->param); + DRM_DEBUG_DRIVER(I915_DRV, "Unknown parameter %d\n", + param->param); return -EINVAL; } @@ -817,7 +819,8 @@ static int i915_setparam(struct drm_device *dev, void *data, dev_priv->fence_reg_start = param->value; break; default: - DRM_DEBUG("unknown parameter %d\n", param->param); + DRM_DEBUG_DRIVER(I915_DRV, "unknown parameter %d\n", + param->param); return -EINVAL; } @@ -865,9 +868,10 @@ static int i915_set_status_page(struct drm_device *dev, void *data, memset(dev_priv->hw_status_page, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); - DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n", - dev_priv->status_gfx_addr); - DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); + DRM_DEBUG_DRIVER(I915_DRV, "load hws HWS_PGA with gfx mem 0x%x\n", + dev_priv->status_gfx_addr); + DRM_DEBUG_DRIVER(I915_DRV, "load hws at %p\n", + dev_priv->hw_status_page); return 0; } @@ -922,7 +926,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, * Some of the preallocated space is taken by the GTT * and popup. GTT is 1K per MB of aperture size, and popup is 4K. */ - if (IS_G4X(dev) || IS_IGD(dev)) + if (IS_G4X(dev) || IS_IGD(dev) || IS_IGDNG(dev)) overhead = 4096; else overhead = (*aperture_size / 1024) + 4096; @@ -1058,7 +1062,7 @@ int i915_master_create(struct drm_device *dev, struct drm_master *master) { struct drm_i915_master_private *master_priv; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (!master_priv) return -ENOMEM; @@ -1073,7 +1077,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) if (!master_priv) return; - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } @@ -1102,12 +1106,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; - dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_i915_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - dev->dev_private = (void *)dev_priv; dev_priv->dev = dev; @@ -1144,17 +1146,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } -#ifdef CONFIG_HIGHMEM64G - /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ - dev_priv->has_gem = 0; -#else /* enable GEM by default */ dev_priv->has_gem = 1; -#endif dev->driver->get_vblank_counter = i915_get_vblank_counter; - if (IS_GM45(dev)) + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (IS_G4X(dev) || IS_IGDNG(dev)) { + dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */ dev->driver->get_vblank_counter = gm45_get_vblank_counter; + } i915_gem_load(dev); @@ -1198,7 +1198,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } /* Must be done after probing outputs */ - intel_opregion_init(dev, 0); + /* FIXME: verify on IGDNG */ + if (!IS_IGDNG(dev)) + intel_opregion_init(dev, 0); return 0; @@ -1207,7 +1209,7 @@ out_iomapfree: out_rmmap: iounmap(dev_priv->regs); free_priv: - drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } @@ -1232,7 +1234,8 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->regs != NULL) iounmap(dev_priv->regs); - intel_opregion_free(dev, 0); + if (!IS_IGDNG(dev)) + intel_opregion_free(dev, 0); if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_modeset_cleanup(dev); @@ -1246,8 +1249,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_lastclose(dev); } - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); return 0; } @@ -1256,17 +1258,16 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv; - DRM_DEBUG("\n"); + DRM_DEBUG_DRIVER(I915_DRV, "\n"); i915_file_priv = (struct drm_i915_file_private *) - drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); + kmalloc(sizeof(*i915_file_priv), GFP_KERNEL); if (!i915_file_priv) return -ENOMEM; file_priv->driver_priv = i915_file_priv; - i915_file_priv->mm.last_gem_seqno = 0; - i915_file_priv->mm.last_gem_throttle_seqno = 0; + INIT_LIST_HEAD(&i915_file_priv->mm.request_list); return 0; } @@ -1303,6 +1304,7 @@ void i915_driver_lastclose(struct drm_device * dev) void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; + i915_gem_release(dev, file_priv); if (!drm_core_check_feature(dev, DRIVER_MODESET)) i915_mem_release(dev, file_priv, dev_priv->agp_heap); } @@ -1311,7 +1313,7 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; - drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); + kfree(i915_file_priv); } struct drm_ioctl_desc i915_ioctls[] = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c431fa54bbb..7a84f04e843 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -126,6 +126,13 @@ struct drm_i915_fence_reg { struct drm_gem_object *obj; }; +struct sdvo_device_mapping { + u8 dvo_port; + u8 slave_addr; + u8 dvo_wiring; + u8 initialized; +}; + typedef struct drm_i915_private { struct drm_device *dev; @@ -143,6 +150,8 @@ typedef struct drm_i915_private { drm_local_map_t hws_map; struct drm_gem_object *hws_obj; + struct resource mch_res; + unsigned int cpp; int back_offset; int front_offset; @@ -158,6 +167,11 @@ typedef struct drm_i915_private { /** Cached value of IMR to avoid reads in updating the bitfield */ u32 irq_mask_reg; u32 pipestat[2]; + /** splitted irq regs for graphics and display engine on IGDNG, + irq_mask_reg is still used for display irq. */ + u32 gt_irq_mask_reg; + u32 gt_irq_enable_reg; + u32 de_irq_enable_reg; u32 hotplug_supported_mask; struct work_struct hotplug_work; @@ -285,6 +299,13 @@ typedef struct drm_i915_private { u8 saveDACMASK; u8 saveCR[37]; uint64_t saveFENCE[16]; + u32 saveCURACNTR; + u32 saveCURAPOS; + u32 saveCURABASE; + u32 saveCURBCNTR; + u32 saveCURBPOS; + u32 saveCURBBASE; + u32 saveCURSIZE; struct { struct drm_mm gtt_space; @@ -382,6 +403,7 @@ typedef struct drm_i915_private { /* storage for physical objects */ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; } mm; + struct sdvo_device_mapping sdvo_mappings[2]; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ @@ -491,13 +513,16 @@ struct drm_i915_gem_request { /** Time at which this request was emitted, in jiffies. */ unsigned long emitted_jiffies; + /** global list entry for this request */ struct list_head list; + + /** file_priv list entry for this request */ + struct list_head client_list; }; struct drm_i915_file_private { struct { - uint32_t last_gem_seqno; - uint32_t last_gem_throttle_seqno; + struct list_head request_list; } mm; }; @@ -621,6 +646,8 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev); +int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); +int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); @@ -642,6 +669,7 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); int i915_gem_object_get_pages(struct drm_gem_object *obj); void i915_gem_object_put_pages(struct drm_gem_object *obj); +void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); /* i915_gem_tiling.c */ void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); @@ -785,7 +813,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x2E02 || \ (dev)->pci_device == 0x2E12 || \ (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32) + (dev)->pci_device == 0x2E32 || \ + (dev)->pci_device == 0x0042 || \ + (dev)->pci_device == 0x0046) #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02 || \ (dev)->pci_device == 0x2A12) @@ -807,20 +837,26 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x29D2 || \ (IS_IGD(dev))) +#define IS_IGDNG_D(dev) ((dev)->pci_device == 0x0042) +#define IS_IGDNG_M(dev) ((dev)->pci_device == 0x0046) +#define IS_IGDNG(dev) (IS_IGDNG_D(dev) || IS_IGDNG_M(dev)) + #define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ - IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev)) + IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev) || \ + IS_IGDNG(dev)) #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev) || \ - IS_IGD(dev)) + IS_IGD(dev) || IS_IGDNG_M(dev)) -#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev)) +#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev) || \ + IS_IGDNG(dev)) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. */ #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev)) +#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 39f5c658ef5..fd2b8bdffe3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,7 +46,6 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); -static int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_evict_something(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, @@ -989,10 +988,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return -ENODEV; /* Only handle setting domains to types used by the CPU. */ - if (write_domain & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + if (write_domain & I915_GEM_GPU_DOMAINS) return -EINVAL; - if (read_domains & ~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) + if (read_domains & I915_GEM_GPU_DOMAINS) return -EINVAL; /* Having something in the write domain implies it's in the read @@ -1158,7 +1157,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Need a new fence register? */ if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, write); + ret = i915_gem_object_get_fence_reg(obj); if (ret) { mutex_unlock(&dev->struct_mutex); return VM_FAULT_SIGBUS; @@ -1208,8 +1207,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) /* Set the object up for mmap'ing */ list = &obj->map_list; - list->map = drm_calloc(1, sizeof(struct drm_map_list), - DRM_MEM_DRIVER); + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); if (!list->map) return -ENOMEM; @@ -1249,7 +1247,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) out_free_mm: drm_mm_put_block(list->file_offset_node); out_free_list: - drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER); + kfree(list->map); return ret; } @@ -1271,7 +1269,7 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) } if (list->map) { - drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER); + kfree(list->map); list->map = NULL; } @@ -1481,15 +1479,20 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj) * Returned sequence numbers are nonzero on success. */ static uint32_t -i915_add_request(struct drm_device *dev, uint32_t flush_domains) +i915_add_request(struct drm_device *dev, struct drm_file *file_priv, + uint32_t flush_domains) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_file_private *i915_file_priv = NULL; struct drm_i915_gem_request *request; uint32_t seqno; int was_empty; RING_LOCALS; - request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER); + if (file_priv != NULL) + i915_file_priv = file_priv->driver_priv; + + request = kzalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) return 0; @@ -1515,6 +1518,12 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains) request->emitted_jiffies = jiffies; was_empty = list_empty(&dev_priv->mm.request_list); list_add_tail(&request->list, &dev_priv->mm.request_list); + if (i915_file_priv) { + list_add_tail(&request->client_list, + &i915_file_priv->mm.request_list); + } else { + INIT_LIST_HEAD(&request->client_list); + } /* Associate any objects on the flushing list matching the write * domain we're flushing with our flush. @@ -1664,7 +1673,8 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_retire_request(dev, request); list_del(&request->list); - drm_free(request, sizeof(*request), DRM_MEM_DRIVER); + list_del(&request->client_list); + kfree(request); } else break; } @@ -1702,7 +1712,10 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno) BUG_ON(seqno == 0); if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) { - ier = I915_READ(IER); + if (IS_IGDNG(dev)) + ier = I915_READ(DEIER) | I915_READ(GTIER); + else + ier = I915_READ(IER); if (!ier) { DRM_ERROR("something (likely vbetool) disabled " "interrupts, re-enabling\n"); @@ -1754,8 +1767,7 @@ i915_gem_flush(struct drm_device *dev, if (flush_domains & I915_GEM_DOMAIN_CPU) drm_agp_chipset_flush(dev); - if ((invalidate_domains | flush_domains) & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) { + if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { /* * read/write caches: * @@ -1977,7 +1989,7 @@ i915_gem_evict_something(struct drm_device *dev) i915_gem_flush(dev, obj->write_domain, obj->write_domain); - i915_add_request(dev, obj->write_domain); + i915_add_request(dev, NULL, obj->write_domain); obj = NULL; continue; @@ -1991,7 +2003,7 @@ i915_gem_evict_something(struct drm_device *dev) /* If we didn't do any of the above, there's nothing to be done * and we just can't fit it in. */ - return -ENOMEM; + return -ENOSPC; } return ret; } @@ -2006,7 +2018,7 @@ i915_gem_evict_everything(struct drm_device *dev) if (ret != 0) break; } - if (ret == -ENOMEM) + if (ret == -ENOSPC) return 0; return ret; } @@ -2149,13 +2161,11 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) val |= I830_FENCE_REG_VALID; I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); - } /** * i915_gem_object_get_fence_reg - set up a fence reg for an object * @obj: object to map through a fence reg - * @write: object is about to be written * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. @@ -2166,8 +2176,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) * It then sets up the reg based on the object's properties: address, pitch * and tiling format. */ -static int -i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write) +int +i915_gem_object_get_fence_reg(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2215,7 +2225,7 @@ try_again: loff_t offset; if (avail == 0) - return -ENOMEM; + return -ENOSPC; for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { @@ -2248,7 +2258,7 @@ try_again: i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); - seqno = i915_add_request(dev, + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); if (seqno == 0) return -ENOMEM; @@ -2317,6 +2327,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) } /** + * i915_gem_object_put_fence_reg - waits on outstanding fenced access + * to the buffer to finish, and then resets the fence register. + * @obj: tiled object holding a fence register. + * + * Zeroes out the fence register itself and clears out the associated + * data structures in dev_priv and obj_priv. + */ +int +i915_gem_object_put_fence_reg(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->fence_reg == I915_FENCE_REG_NONE) + return 0; + + /* On the i915, GPU access to tiled buffers is via a fence, + * therefore we must wait for any outstanding access to complete + * before clearing the fence. + */ + if (!IS_I965G(dev)) { + int ret; + + i915_gem_object_flush_gpu_write_domain(obj); + i915_gem_object_flush_gtt_write_domain(obj); + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) + return ret; + } + + i915_gem_clear_fence_reg (obj); + + return 0; +} + +/** * Finds free space in the GTT aperture and binds the object there. */ static int @@ -2364,7 +2410,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) spin_unlock(&dev_priv->mm.active_list_lock); if (lists_empty) { DRM_ERROR("GTT full, but LRU list empty\n"); - return -ENOMEM; + return -ENOSPC; } ret = i915_gem_evict_something(dev); @@ -2409,8 +2455,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) * wasn't in the GTT, there shouldn't be any way it could have been in * a GPU cache */ - BUG_ON(obj->read_domains & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); - BUG_ON(obj->write_domain & ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); + BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS); + BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS); return 0; } @@ -2452,7 +2498,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) /* Queue the GPU write cache flushing we need. */ i915_gem_flush(dev, 0, obj->write_domain); - seqno = i915_add_request(dev, obj->write_domain); + seqno = i915_add_request(dev, NULL, obj->write_domain); obj->write_domain = 0; i915_gem_object_move_to_active(obj, seqno); } @@ -2786,8 +2832,7 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) /* Free the page_cpu_valid mappings which are now stale, whether * or not we've got I915_GEM_DOMAIN_CPU. */ - drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); obj_priv->page_cpu_valid = NULL; } @@ -2829,8 +2874,8 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, * newly adding I915_GEM_DOMAIN_CPU */ if (obj_priv->page_cpu_valid == NULL) { - obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + obj_priv->page_cpu_valid = kzalloc(obj->size / PAGE_SIZE, + GFP_KERNEL); if (obj_priv->page_cpu_valid == NULL) return -ENOMEM; } else if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) @@ -3035,20 +3080,12 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; int nbox = exec->num_cliprects; int i = 0, count; - uint32_t exec_start, exec_len; + uint32_t exec_start, exec_len; RING_LOCALS; exec_start = (uint32_t) exec_offset + exec->batch_start_offset; exec_len = (uint32_t) exec->batch_len; - if ((exec_start | exec_len) & 0x7) { - DRM_ERROR("alignment\n"); - return -EINVAL; - } - - if (!exec_start) - return -EINVAL; - count = nbox ? nbox : 1; for (i = 0; i < count; i++) { @@ -3089,6 +3126,10 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev, /* Throttle our rendering by waiting until the ring has completed our requests * emitted over 20 msec ago. * + * Note that if we were to use the current jiffies each time around the loop, + * we wouldn't escape the function with any frames outstanding if the time to + * render a frame was over 20ms. + * * This should get us reasonable parallelism between CPU and GPU but also * relatively low latency when blocking on a particular request to finish. */ @@ -3097,15 +3138,25 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; int ret = 0; - uint32_t seqno; + unsigned long recent_enough = jiffies - msecs_to_jiffies(20); mutex_lock(&dev->struct_mutex); - seqno = i915_file_priv->mm.last_gem_throttle_seqno; - i915_file_priv->mm.last_gem_throttle_seqno = - i915_file_priv->mm.last_gem_seqno; - if (seqno) - ret = i915_wait_request(dev, seqno); + while (!list_empty(&i915_file_priv->mm.request_list)) { + struct drm_i915_gem_request *request; + + request = list_first_entry(&i915_file_priv->mm.request_list, + struct drm_i915_gem_request, + client_list); + + if (time_after_eq(request->emitted_jiffies, recent_enough)) + break; + + ret = i915_wait_request(dev, request->seqno); + if (ret != 0) + break; + } mutex_unlock(&dev->struct_mutex); + return ret; } @@ -3182,12 +3233,29 @@ err: return ret; } +static int +i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer *exec, + uint64_t exec_offset) +{ + uint32_t exec_start, exec_len; + + exec_start = (uint32_t) exec_offset + exec->batch_start_offset; + exec_len = (uint32_t) exec->batch_len; + + if ((exec_start | exec_len) & 0x7) + return -EINVAL; + + if (!exec_start) + return -EINVAL; + + return 0; +} + int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; struct drm_i915_gem_execbuffer *args = data; struct drm_i915_gem_exec_object *exec_list = NULL; struct drm_gem_object **object_list = NULL; @@ -3230,8 +3298,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, } if (args->num_cliprects != 0) { - cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects), - DRM_MEM_DRIVER); + cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), + GFP_KERNEL); if (cliprects == NULL) goto pre_mutex_err; @@ -3312,7 +3380,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, break; /* error other than GTT full, or we've already tried again */ - if (ret != -ENOMEM || pin_tries >= 1) { + if (ret != -ENOSPC || pin_tries >= 1) { if (ret != -ERESTARTSYS) DRM_ERROR("Failed to pin buffers %d\n", ret); goto err; @@ -3331,8 +3399,20 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, /* Set the pending read domains for the batch buffer to COMMAND */ batch_obj = object_list[args->buffer_count-1]; - batch_obj->pending_read_domains = I915_GEM_DOMAIN_COMMAND; - batch_obj->pending_write_domain = 0; + if (batch_obj->pending_write_domain) { + DRM_ERROR("Attempting to use self-modifying batch buffer\n"); + ret = -EINVAL; + goto err; + } + batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND; + + /* Sanity check the batch buffer, prior to moving objects */ + exec_offset = exec_list[args->buffer_count - 1].offset; + ret = i915_gem_check_execbuffer (args, exec_offset); + if (ret != 0) { + DRM_ERROR("execbuf with invalid offset/length\n"); + goto err; + } i915_verify_inactive(dev, __FILE__, __LINE__); @@ -3363,7 +3443,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, dev->invalidate_domains, dev->flush_domains); if (dev->flush_domains) - (void)i915_add_request(dev, dev->flush_domains); + (void)i915_add_request(dev, file_priv, + dev->flush_domains); } for (i = 0; i < args->buffer_count; i++) { @@ -3381,8 +3462,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, } #endif - exec_offset = exec_list[args->buffer_count - 1].offset; - #if WATCH_EXEC i915_gem_dump_object(batch_obj, args->batch_len, @@ -3412,9 +3491,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, * *some* interrupts representing completion of buffers that we can * wait on when trying to clear up gtt space). */ - seqno = i915_add_request(dev, flush_domains); + seqno = i915_add_request(dev, file_priv, flush_domains); BUG_ON(seqno == 0); - i915_file_priv->mm.last_gem_seqno = seqno; for (i = 0; i < args->buffer_count; i++) { struct drm_gem_object *obj = object_list[i]; @@ -3474,8 +3552,7 @@ err: pre_mutex_err: drm_free_large(object_list); drm_free_large(exec_list); - drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -3503,7 +3580,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (!IS_I965G(dev) && obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, true); + ret = i915_gem_object_get_fence_reg(obj); if (ret != 0) { if (ret != -EBUSY && ret != -ERESTARTSYS) DRM_ERROR("Failure to install fence: %d\n", @@ -3520,8 +3597,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) atomic_inc(&dev->pin_count); atomic_add(obj->size, &dev->pin_memory); if (!obj_priv->active && - (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) == 0 && + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0 && !list_empty(&obj_priv->list)) list_del_init(&obj_priv->list); } @@ -3548,8 +3624,7 @@ i915_gem_object_unpin(struct drm_gem_object *obj) */ if (obj_priv->pin_count == 0) { if (!obj_priv->active && - (obj->write_domain & ~(I915_GEM_DOMAIN_CPU | - I915_GEM_DOMAIN_GTT)) == 0) + (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list); atomic_dec(&dev->pin_count); @@ -3653,15 +3728,14 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n", args->handle); - mutex_unlock(&dev->struct_mutex); return -EBADF; } + mutex_lock(&dev->struct_mutex); /* Update the active list for the hardware's current position. * Otherwise this only updates on a delayed timer or when irqs are * actually unmasked, and our working set ends up being larger than @@ -3695,7 +3769,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv; - obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER); + obj_priv = kzalloc(sizeof(*obj_priv), GFP_KERNEL); if (obj_priv == NULL) return -ENOMEM; @@ -3733,9 +3807,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) i915_gem_free_mmap_offset(obj); - drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); kfree(obj_priv->bit_17); - drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); + kfree(obj->driver_private); } /** Unbinds all objects that are on the given buffer list. */ @@ -3800,9 +3874,8 @@ i915_gem_idle(struct drm_device *dev) /* Flush the GPU along with all non-CPU write domains */ - i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), - ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); - seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU); + i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS); if (seqno == 0) { mutex_unlock(&dev->struct_mutex); @@ -4190,7 +4263,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, if (dev_priv->mm.phys_objs[id - 1] || !size) return 0; - phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + phys_obj = kzalloc(sizeof(struct drm_i915_gem_phys_object), GFP_KERNEL); if (!phys_obj) return -ENOMEM; @@ -4209,7 +4282,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, return 0; kfree_obj: - drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + kfree(phys_obj); return ret; } @@ -4269,6 +4342,8 @@ void i915_gem_detach_phys_object(struct drm_device *dev, } drm_clflush_pages(obj_priv->pages, page_count); drm_agp_chipset_flush(dev); + + i915_gem_object_put_pages(obj); out: obj_priv->phys_obj->cur_obj = NULL; obj_priv->phys_obj = NULL; @@ -4326,6 +4401,8 @@ i915_gem_attach_phys_object(struct drm_device *dev, kunmap_atomic(src, KM_USER0); } + i915_gem_object_put_pages(obj); + return 0; out: return ret; @@ -4352,3 +4429,17 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, drm_agp_chipset_flush(dev); return 0; } + +void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv) +{ + struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; + + /* Clean up our request list when the client is going away, so that + * later retire_requests won't dereference our soon-to-be-gone + * file_priv. + */ + mutex_lock(&dev->struct_mutex); + while (!list_empty(&i915_file_priv->mm.request_list)) + list_del_init(i915_file_priv->mm.request_list.next); + mutex_unlock(&dev->struct_mutex); +} diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 986f1082c59..28146e405e8 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -104,7 +104,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) if (obj->name) seq_printf(m, " (name: %d)", obj->name); if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d\n", obj_priv->fence_reg); + seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg); seq_printf(m, "\n"); } @@ -318,7 +318,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingTail : %08x\n", tail); seq_printf(m, "RingMask : %08x\n", mask); seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size); - seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 540dd336e6e..5c1ceec49f5 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -25,6 +25,8 @@ * */ +#include <linux/acpi.h> +#include <linux/pnp.h> #include "linux/string.h" #include "linux/bitops.h" #include "drmP.h" @@ -81,6 +83,143 @@ * to match what the GPU expects. */ +#define MCHBAR_I915 0x44 +#define MCHBAR_I965 0x48 +#define MCHBAR_SIZE (4*4096) + +#define DEVEN_REG 0x54 +#define DEVEN_MCHBAR_EN (1 << 28) + +/* Allocate space for the MCH regs if needed, return nonzero on error */ +static int +intel_alloc_mchbar_resource(struct drm_device *dev) +{ + struct pci_dev *bridge_dev; + drm_i915_private_t *dev_priv = dev->dev_private; + int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp_lo, temp_hi = 0; + u64 mchbar_addr; + int ret = 0; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + ret = -ENODEV; + goto out; + } + + if (IS_I965G(dev)) + pci_read_config_dword(bridge_dev, reg + 4, &temp_hi); + pci_read_config_dword(bridge_dev, reg, &temp_lo); + mchbar_addr = ((u64)temp_hi << 32) | temp_lo; + + /* If ACPI doesn't have it, assume we need to allocate it ourselves */ + if (mchbar_addr && + pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) { + ret = 0; + goto out_put; + } + + /* Get some space for it */ + ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res, + MCHBAR_SIZE, MCHBAR_SIZE, + PCIBIOS_MIN_MEM, + 0, pcibios_align_resource, + bridge_dev); + if (ret) { + DRM_DEBUG("failed bus alloc: %d\n", ret); + dev_priv->mch_res.start = 0; + goto out_put; + } + + if (IS_I965G(dev)) + pci_write_config_dword(bridge_dev, reg + 4, + upper_32_bits(dev_priv->mch_res.start)); + + pci_write_config_dword(bridge_dev, reg, + lower_32_bits(dev_priv->mch_res.start)); +out_put: + pci_dev_put(bridge_dev); +out: + return ret; +} + +/* Setup MCHBAR if possible, return true if we should disable it again */ +static bool +intel_setup_mchbar(struct drm_device *dev) +{ + struct pci_dev *bridge_dev; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + bool need_disable = false, enabled; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + goto out; + } + + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(bridge_dev, DEVEN_REG, &temp); + enabled = !!(temp & DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + enabled = temp & 1; + } + + /* If it's already enabled, don't have to do anything */ + if (enabled) + goto out_put; + + if (intel_alloc_mchbar_resource(dev)) + goto out_put; + + need_disable = true; + + /* Space is allocated or reserved, so enable it. */ + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_write_config_dword(bridge_dev, DEVEN_REG, + temp | DEVEN_MCHBAR_EN); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + pci_write_config_dword(bridge_dev, mchbar_reg, temp | 1); + } +out_put: + pci_dev_put(bridge_dev); +out: + return need_disable; +} + +static void +intel_teardown_mchbar(struct drm_device *dev, bool disable) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct pci_dev *bridge_dev; + int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915; + u32 temp; + + bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (!bridge_dev) { + DRM_DEBUG("no bridge dev?!\n"); + return; + } + + if (disable) { + if (IS_I915G(dev) || IS_I915GM(dev)) { + pci_read_config_dword(bridge_dev, DEVEN_REG, &temp); + temp &= ~DEVEN_MCHBAR_EN; + pci_write_config_dword(bridge_dev, DEVEN_REG, temp); + } else { + pci_read_config_dword(bridge_dev, mchbar_reg, &temp); + temp &= ~1; + pci_write_config_dword(bridge_dev, mchbar_reg, temp); + } + } + + if (dev_priv->mch_res.start) + release_resource(&dev_priv->mch_res); +} + /** * Detects bit 6 swizzling of address lookup between IGD access and CPU * access through main memory. @@ -91,6 +230,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + bool need_disable; if (!IS_I9XX(dev)) { /* As far as we know, the 865 doesn't have these bit 6 @@ -101,6 +241,9 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } else if (IS_MOBILE(dev)) { uint32_t dcc; + /* Try to make sure MCHBAR is enabled before poking at it */ + need_disable = intel_setup_mchbar(dev); + /* On mobile 9xx chipsets, channel interleave by the CPU is * determined by DCC. For single-channel, neither the CPU * nor the GPU do swizzling. For dual channel interleaved, @@ -140,6 +283,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; } + + intel_teardown_mchbar(dev, need_disable); } else { /* The 965, G33, and newer, have a very flexible memory * configuration. It will enable dual-channel mode @@ -170,6 +315,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) } } + /* FIXME: check with memory config on IGDNG */ + if (IS_IGDNG(dev)) { + DRM_ERROR("disable tiling on IGDNG...\n"); + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } + dev_priv->mm.bit_6_swizzle_x = swizzle_x; dev_priv->mm.bit_6_swizzle_y = swizzle_y; } @@ -256,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) if (stride & (stride - 1)) return false; - /* We don't handle the aperture area covered by the fence being bigger + /* We don't 0handle the aperture area covered by the fence being bigger * than the object size. */ if (i915_get_fence_size(dev, size) != size) @@ -265,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) return true; } +static bool +i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->gtt_space == NULL) + return true; + + if (tiling_mode == I915_TILING_NONE) + return true; + + if (!IS_I965G(dev)) { + if (obj_priv->gtt_offset & (obj->size - 1)) + return false; + if (IS_I9XX(dev)) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; + } else { + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + return false; + } + } + + return true; +} + /** * Sets the tiling mode of an object, returning the required swizzling of * bit 6 of addresses in the object. @@ -277,6 +456,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -284,14 +464,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj_priv = obj->driver_private; if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } - mutex_lock(&dev->struct_mutex); - if (args->tiling_mode == I915_TILING_NONE) { args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } else { if (args->tiling_mode == I915_TILING_X) args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; @@ -314,32 +495,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { args->tiling_mode = I915_TILING_NONE; args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } } - if (args->tiling_mode != obj_priv->tiling_mode) { - int ret; - /* Unbind the object, as switching tiling means we're - * switching the cache organization due to fencing, probably. + mutex_lock(&dev->struct_mutex); + if (args->tiling_mode != obj_priv->tiling_mode || + args->stride != obj_priv->stride) { + /* We need to rebind the object if its current allocation + * no longer meets the alignment restrictions for its new + * tiling mode. Otherwise we can just leave it alone, but + * need to ensure that any fence register is cleared. */ - ret = i915_gem_object_unbind(obj); + if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) + ret = i915_gem_object_unbind(obj); + else + ret = i915_gem_object_put_fence_reg(obj); if (ret != 0) { WARN(ret != -ERESTARTSYS, - "failed to unbind object for tiling switch"); + "failed to reset object for tiling switch"); args->tiling_mode = obj_priv->tiling_mode; - mutex_unlock(&dev->struct_mutex); - drm_gem_object_unreference(obj); - - return ret; + args->stride = obj_priv->stride; + goto err; } + obj_priv->tiling_mode = args->tiling_mode; + obj_priv->stride = args->stride; } - obj_priv->stride = args->stride; - +err: drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 98bb4c878c4..b86b7b7130c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -58,6 +58,47 @@ DRM_I915_VBLANK_PIPE_B) void +igdng_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->gt_irq_mask_reg & mask) != 0) { + dev_priv->gt_irq_mask_reg &= ~mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + (void) I915_READ(GTIMR); + } +} + +static inline void +igdng_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->gt_irq_mask_reg & mask) != mask) { + dev_priv->gt_irq_mask_reg |= mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + (void) I915_READ(GTIMR); + } +} + +/* For display hotplug interrupt */ +void +igdng_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->irq_mask_reg & mask) != 0) { + dev_priv->irq_mask_reg &= ~mask; + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + (void) I915_READ(DEIMR); + } +} + +static inline void +igdng_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) +{ + if ((dev_priv->irq_mask_reg & mask) != mask) { + dev_priv->irq_mask_reg |= mask; + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + (void) I915_READ(DEIMR); + } +} + +void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) { if ((dev_priv->irq_mask_reg & mask) != 0) { @@ -196,6 +237,47 @@ static void i915_hotplug_work_func(struct work_struct *work) drm_sysfs_hotplug_event(dev); } +irqreturn_t igdng_irq_handler(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret = IRQ_NONE; + u32 de_iir, gt_iir; + u32 new_de_iir, new_gt_iir; + struct drm_i915_master_private *master_priv; + + de_iir = I915_READ(DEIIR); + gt_iir = I915_READ(GTIIR); + + for (;;) { + if (de_iir == 0 && gt_iir == 0) + break; + + ret = IRQ_HANDLED; + + I915_WRITE(DEIIR, de_iir); + new_de_iir = I915_READ(DEIIR); + I915_WRITE(GTIIR, gt_iir); + new_gt_iir = I915_READ(GTIIR); + + if (dev->primary->master) { + master_priv = dev->primary->master->driver_priv; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + } + + if (gt_iir & GT_USER_INTERRUPT) { + dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); + DRM_WAKEUP(&dev_priv->irq_queue); + } + + de_iir = new_de_iir; + gt_iir = new_gt_iir; + } + + return ret; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -212,6 +294,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&dev_priv->irq_received); + if (IS_IGDNG(dev)) + return igdng_irq_handler(dev); + iir = I915_READ(IIR); if (IS_I965G(dev)) { @@ -349,8 +434,12 @@ void i915_user_irq_get(struct drm_device *dev) unsigned long irqflags; spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); - if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { + if (IS_IGDNG(dev)) + igdng_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + else + i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -361,8 +450,12 @@ void i915_user_irq_put(struct drm_device *dev) spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); - if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + if (IS_IGDNG(dev)) + igdng_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + else + i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + } spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); } @@ -455,6 +548,9 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) if (!(pipeconf & PIPEACONF_ENABLE)) return -EINVAL; + if (IS_IGDNG(dev)) + return 0; + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, pipe, @@ -474,6 +570,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; unsigned long irqflags; + if (IS_IGDNG(dev)) + return; + spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); i915_disable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE | @@ -484,7 +583,9 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - opregion_enable_asle(dev); + + if (!IS_IGDNG(dev)) + opregion_enable_asle(dev); dev_priv->irq_enabled = 1; } @@ -545,12 +646,65 @@ int i915_vblank_swap(struct drm_device *dev, void *data, /* drm_dma.h hooks */ +static void igdng_irq_preinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE(HWSTAM, 0xeffe); + + /* XXX hotplug from PCH */ + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + (void) I915_READ(DEIER); + + /* and GT */ + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + (void) I915_READ(GTIER); +} + +static int igdng_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + /* enable kind of interrupts always enabled */ + u32 display_mask = DE_MASTER_IRQ_CONTROL /*| DE_PCH_EVENT */; + u32 render_mask = GT_USER_INTERRUPT; + + dev_priv->irq_mask_reg = ~display_mask; + dev_priv->de_irq_enable_reg = display_mask; + + /* should always can generate irq */ + I915_WRITE(DEIIR, I915_READ(DEIIR)); + I915_WRITE(DEIMR, dev_priv->irq_mask_reg); + I915_WRITE(DEIER, dev_priv->de_irq_enable_reg); + (void) I915_READ(DEIER); + + /* user interrupt should be enabled, but masked initial */ + dev_priv->gt_irq_mask_reg = 0xffffffff; + dev_priv->gt_irq_enable_reg = render_mask; + + I915_WRITE(GTIIR, I915_READ(GTIIR)); + I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg); + I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); + (void) I915_READ(GTIER); + + return 0; +} + void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; atomic_set(&dev_priv->irq_received, 0); + INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); + + if (IS_IGDNG(dev)) { + igdng_irq_preinstall(dev); + return; + } + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); @@ -562,7 +716,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev) I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); (void) I915_READ(IER); - INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); } int i915_driver_irq_postinstall(struct drm_device *dev) @@ -570,9 +723,12 @@ int i915_driver_irq_postinstall(struct drm_device *dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + if (IS_IGDNG(dev)) + return igdng_irq_postinstall(dev); /* Unmask the interrupts that we always want on. */ dev_priv->irq_mask_reg = ~I915_INTERRUPT_ENABLE_FIX; @@ -613,11 +769,24 @@ int i915_driver_irq_postinstall(struct drm_device *dev) (void) I915_READ(IER); opregion_enable_asle(dev); - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); return 0; } +static void igdng_irq_uninstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + I915_WRITE(HWSTAM, 0xffffffff); + + I915_WRITE(DEIMR, 0xffffffff); + I915_WRITE(DEIER, 0x0); + I915_WRITE(DEIIR, I915_READ(DEIIR)); + + I915_WRITE(GTIMR, 0xffffffff); + I915_WRITE(GTIER, 0x0); + I915_WRITE(GTIIR, I915_READ(GTIIR)); +} + void i915_driver_irq_uninstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -627,6 +796,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->vblank_pipe = 0; + if (IS_IGDNG(dev)) { + igdng_irq_uninstall(dev); + return; + } + if (I915_HAS_HOTPLUG(dev)) { I915_WRITE(PORT_HOTPLUG_EN, 0); I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 96e271986d2..83b7b81bb2b 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c @@ -94,8 +94,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start; @@ -111,8 +111,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start + size; @@ -169,7 +169,7 @@ static void free_block(struct mem_block *p) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } if (p->prev->file_priv == NULL) { @@ -177,7 +177,7 @@ static void free_block(struct mem_block *p) q->size += p->size; q->next = p->next; q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(p); } } @@ -185,14 +185,14 @@ static void free_block(struct mem_block *p) */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS); + struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); if (!blocks) return -ENOMEM; - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS); + *heap = kmalloc(sizeof(**heap), GFP_KERNEL); if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS); + kfree(blocks); return -ENOMEM; } @@ -233,7 +233,7 @@ void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } } } @@ -250,10 +250,10 @@ void i915_mem_takedown(struct mem_block **heap) for (p = (*heap)->next; p != *heap;) { struct mem_block *q = p; p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } - drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS); + kfree(*heap); *heap = NULL; } diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index dc425e74a26..e4b4e8898e3 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -419,7 +419,7 @@ void intel_opregion_free(struct drm_device *dev, int suspend) return; if (!suspend) - acpi_video_exit(); + acpi_video_unregister(); opregion->acpi->drdy = 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 375569d01d0..f6237a0b113 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -450,6 +450,13 @@ #define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) #define PLL_REF_INPUT_MASK (3 << 13) #define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* IGDNG */ +# define PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT 9 +# define PLL_REF_SDVO_HDMI_MULTIPLIER_MASK (7 << 9) +# define PLL_REF_SDVO_HDMI_MULTIPLIER(x) (((x)-1) << 9) +# define DPLL_FPA1_P1_POST_DIV_SHIFT 0 +# define DPLL_FPA1_P1_POST_DIV_MASK 0xff + /* * Parallel to Serial Load Pulse phase selection. * Selects the phase for the 10X DPLL clock for the PCIe @@ -631,8 +638,11 @@ /* Hotplug control (945+ only) */ #define PORT_HOTPLUG_EN 0x61110 #define HDMIB_HOTPLUG_INT_EN (1 << 29) +#define DPB_HOTPLUG_INT_EN (1 << 29) #define HDMIC_HOTPLUG_INT_EN (1 << 28) +#define DPC_HOTPLUG_INT_EN (1 << 28) #define HDMID_HOTPLUG_INT_EN (1 << 27) +#define DPD_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -665,8 +675,11 @@ #define PORT_HOTPLUG_STAT 0x61114 #define HDMIB_HOTPLUG_INT_STATUS (1 << 29) +#define DPB_HOTPLUG_INT_STATUS (1 << 29) #define HDMIC_HOTPLUG_INT_STATUS (1 << 28) +#define DPC_HOTPLUG_INT_STATUS (1 << 28) #define HDMID_HOTPLUG_INT_STATUS (1 << 27) +#define DPD_HOTPLUG_INT_STATUS (1 << 27) #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) #define CRT_HOTPLUG_MONITOR_MASK (3 << 8) @@ -951,15 +964,15 @@ # define DAC_A_1_3_V (0 << 4) # define DAC_A_1_1_V (1 << 4) # define DAC_A_0_7_V (2 << 4) -# define DAC_A_OFF (3 << 4) +# define DAC_A_MASK (3 << 4) # define DAC_B_1_3_V (0 << 2) # define DAC_B_1_1_V (1 << 2) # define DAC_B_0_7_V (2 << 2) -# define DAC_B_OFF (3 << 2) +# define DAC_B_MASK (3 << 2) # define DAC_C_1_3_V (0 << 0) # define DAC_C_1_1_V (1 << 0) # define DAC_C_0_7_V (2 << 0) -# define DAC_C_OFF (3 << 0) +# define DAC_C_MASK (3 << 0) /** * CSC coefficients are stored in a floating point format with 9 bits of @@ -1328,6 +1341,163 @@ #define TV_V_CHROMA_0 0x68400 #define TV_V_CHROMA_42 0x684a8 +/* Display Port */ +#define DP_B 0x64100 +#define DP_C 0x64200 +#define DP_D 0x64300 + +#define DP_PORT_EN (1 << 31) +#define DP_PIPEB_SELECT (1 << 30) + +/* Link training mode - select a suitable mode for each stage */ +#define DP_LINK_TRAIN_PAT_1 (0 << 28) +#define DP_LINK_TRAIN_PAT_2 (1 << 28) +#define DP_LINK_TRAIN_PAT_IDLE (2 << 28) +#define DP_LINK_TRAIN_OFF (3 << 28) +#define DP_LINK_TRAIN_MASK (3 << 28) +#define DP_LINK_TRAIN_SHIFT 28 + +/* Signal voltages. These are mostly controlled by the other end */ +#define DP_VOLTAGE_0_4 (0 << 25) +#define DP_VOLTAGE_0_6 (1 << 25) +#define DP_VOLTAGE_0_8 (2 << 25) +#define DP_VOLTAGE_1_2 (3 << 25) +#define DP_VOLTAGE_MASK (7 << 25) +#define DP_VOLTAGE_SHIFT 25 + +/* Signal pre-emphasis levels, like voltages, the other end tells us what + * they want + */ +#define DP_PRE_EMPHASIS_0 (0 << 22) +#define DP_PRE_EMPHASIS_3_5 (1 << 22) +#define DP_PRE_EMPHASIS_6 (2 << 22) +#define DP_PRE_EMPHASIS_9_5 (3 << 22) +#define DP_PRE_EMPHASIS_MASK (7 << 22) +#define DP_PRE_EMPHASIS_SHIFT 22 + +/* How many wires to use. I guess 3 was too hard */ +#define DP_PORT_WIDTH_1 (0 << 19) +#define DP_PORT_WIDTH_2 (1 << 19) +#define DP_PORT_WIDTH_4 (3 << 19) +#define DP_PORT_WIDTH_MASK (7 << 19) + +/* Mystic DPCD version 1.1 special mode */ +#define DP_ENHANCED_FRAMING (1 << 18) + +/** locked once port is enabled */ +#define DP_PORT_REVERSAL (1 << 15) + +/** sends the clock on lane 15 of the PEG for debug */ +#define DP_CLOCK_OUTPUT_ENABLE (1 << 13) + +#define DP_SCRAMBLING_DISABLE (1 << 12) + +/** limit RGB values to avoid confusing TVs */ +#define DP_COLOR_RANGE_16_235 (1 << 8) + +/** Turn on the audio link */ +#define DP_AUDIO_OUTPUT_ENABLE (1 << 6) + +/** vs and hs sync polarity */ +#define DP_SYNC_VS_HIGH (1 << 4) +#define DP_SYNC_HS_HIGH (1 << 3) + +/** A fantasy */ +#define DP_DETECTED (1 << 2) + +/** The aux channel provides a way to talk to the + * signal sink for DDC etc. Max packet size supported + * is 20 bytes in each direction, hence the 5 fixed + * data registers + */ +#define DPB_AUX_CH_CTL 0x64110 +#define DPB_AUX_CH_DATA1 0x64114 +#define DPB_AUX_CH_DATA2 0x64118 +#define DPB_AUX_CH_DATA3 0x6411c +#define DPB_AUX_CH_DATA4 0x64120 +#define DPB_AUX_CH_DATA5 0x64124 + +#define DPC_AUX_CH_CTL 0x64210 +#define DPC_AUX_CH_DATA1 0x64214 +#define DPC_AUX_CH_DATA2 0x64218 +#define DPC_AUX_CH_DATA3 0x6421c +#define DPC_AUX_CH_DATA4 0x64220 +#define DPC_AUX_CH_DATA5 0x64224 + +#define DPD_AUX_CH_CTL 0x64310 +#define DPD_AUX_CH_DATA1 0x64314 +#define DPD_AUX_CH_DATA2 0x64318 +#define DPD_AUX_CH_DATA3 0x6431c +#define DPD_AUX_CH_DATA4 0x64320 +#define DPD_AUX_CH_DATA5 0x64324 + +#define DP_AUX_CH_CTL_SEND_BUSY (1 << 31) +#define DP_AUX_CH_CTL_DONE (1 << 30) +#define DP_AUX_CH_CTL_INTERRUPT (1 << 29) +#define DP_AUX_CH_CTL_TIME_OUT_ERROR (1 << 28) +#define DP_AUX_CH_CTL_TIME_OUT_400us (0 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_600us (1 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_800us (2 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_1600us (3 << 26) +#define DP_AUX_CH_CTL_TIME_OUT_MASK (3 << 26) +#define DP_AUX_CH_CTL_RECEIVE_ERROR (1 << 25) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_MASK (0x1f << 20) +#define DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT 20 +#define DP_AUX_CH_CTL_PRECHARGE_2US_MASK (0xf << 16) +#define DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT 16 +#define DP_AUX_CH_CTL_AUX_AKSV_SELECT (1 << 15) +#define DP_AUX_CH_CTL_MANCHESTER_TEST (1 << 14) +#define DP_AUX_CH_CTL_SYNC_TEST (1 << 13) +#define DP_AUX_CH_CTL_DEGLITCH_TEST (1 << 12) +#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff) +#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0 + +/* + * Computing GMCH M and N values for the Display Port link + * + * GMCH M/N = dot clock * bytes per pixel / ls_clk * # of lanes + * + * ls_clk (we assume) is the DP link clock (1.62 or 2.7 GHz) + * + * The GMCH value is used internally + * + * bytes_per_pixel is the number of bytes coming out of the plane, + * which is after the LUTs, so we want the bytes for our color format. + * For our current usage, this is always 3, one byte for R, G and B. + */ +#define PIPEA_GMCH_DATA_M 0x70050 +#define PIPEB_GMCH_DATA_M 0x71050 + +/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */ +#define PIPE_GMCH_DATA_M_TU_SIZE_MASK (0x3f << 25) +#define PIPE_GMCH_DATA_M_TU_SIZE_SHIFT 25 + +#define PIPE_GMCH_DATA_M_MASK (0xffffff) + +#define PIPEA_GMCH_DATA_N 0x70054 +#define PIPEB_GMCH_DATA_N 0x71054 +#define PIPE_GMCH_DATA_N_MASK (0xffffff) + +/* + * Computing Link M and N values for the Display Port link + * + * Link M / N = pixel_clock / ls_clk + * + * (the DP spec calls pixel_clock the 'strm_clk') + * + * The Link value is transmitted in the Main Stream + * Attributes and VB-ID. + */ + +#define PIPEA_DP_LINK_M 0x70060 +#define PIPEB_DP_LINK_M 0x71060 +#define PIPEA_DP_LINK_M_MASK (0xffffff) + +#define PIPEA_DP_LINK_N 0x70064 +#define PIPEB_DP_LINK_N 0x71064 +#define PIPEA_DP_LINK_N_MASK (0xffffff) + /* Display & cursor control */ /* Pipe A */ @@ -1517,4 +1687,444 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +/* IGDNG */ + +#define CPU_VGACNTRL 0x41000 + +#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030 +#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4) +#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2) +#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2) +#define DIGITAL_PORTA_NO_DETECT (0 << 0) +#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1) +#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0) + +/* refresh rate hardware control */ +#define RR_HW_CTL 0x45300 +#define RR_HW_LOW_POWER_FRAMES_MASK 0xff +#define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 + +#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_BIOS_1 0x46004 +#define FDI_PLL_BIOS_2 0x46008 +#define DISPLAY_PORT_PLL_BIOS_0 0x4600c +#define DISPLAY_PORT_PLL_BIOS_1 0x46010 +#define DISPLAY_PORT_PLL_BIOS_2 0x46014 + +#define FDI_PLL_FREQ_CTL 0x46030 +#define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) +#define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 +#define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff + + +#define PIPEA_DATA_M1 0x60030 +#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ +#define TU_SIZE_MASK 0x7e000000 +#define PIPEA_DATA_M1_OFFSET 0 +#define PIPEA_DATA_N1 0x60034 +#define PIPEA_DATA_N1_OFFSET 0 + +#define PIPEA_DATA_M2 0x60038 +#define PIPEA_DATA_M2_OFFSET 0 +#define PIPEA_DATA_N2 0x6003c +#define PIPEA_DATA_N2_OFFSET 0 + +#define PIPEA_LINK_M1 0x60040 +#define PIPEA_LINK_M1_OFFSET 0 +#define PIPEA_LINK_N1 0x60044 +#define PIPEA_LINK_N1_OFFSET 0 + +#define PIPEA_LINK_M2 0x60048 +#define PIPEA_LINK_M2_OFFSET 0 +#define PIPEA_LINK_N2 0x6004c +#define PIPEA_LINK_N2_OFFSET 0 + +/* PIPEB timing regs are same start from 0x61000 */ + +#define PIPEB_DATA_M1 0x61030 +#define PIPEB_DATA_M1_OFFSET 0 +#define PIPEB_DATA_N1 0x61034 +#define PIPEB_DATA_N1_OFFSET 0 + +#define PIPEB_DATA_M2 0x61038 +#define PIPEB_DATA_M2_OFFSET 0 +#define PIPEB_DATA_N2 0x6103c +#define PIPEB_DATA_N2_OFFSET 0 + +#define PIPEB_LINK_M1 0x61040 +#define PIPEB_LINK_M1_OFFSET 0 +#define PIPEB_LINK_N1 0x61044 +#define PIPEB_LINK_N1_OFFSET 0 + +#define PIPEB_LINK_M2 0x61048 +#define PIPEB_LINK_M2_OFFSET 0 +#define PIPEB_LINK_N2 0x6104c +#define PIPEB_LINK_N2_OFFSET 0 + +/* CPU panel fitter */ +#define PFA_CTL_1 0x68080 +#define PFB_CTL_1 0x68880 +#define PF_ENABLE (1<<31) + +/* legacy palette */ +#define LGC_PALETTE_A 0x4a000 +#define LGC_PALETTE_B 0x4a800 + +/* interrupts */ +#define DE_MASTER_IRQ_CONTROL (1 << 31) +#define DE_SPRITEB_FLIP_DONE (1 << 29) +#define DE_SPRITEA_FLIP_DONE (1 << 28) +#define DE_PLANEB_FLIP_DONE (1 << 27) +#define DE_PLANEA_FLIP_DONE (1 << 26) +#define DE_PCU_EVENT (1 << 25) +#define DE_GTT_FAULT (1 << 24) +#define DE_POISON (1 << 23) +#define DE_PERFORM_COUNTER (1 << 22) +#define DE_PCH_EVENT (1 << 21) +#define DE_AUX_CHANNEL_A (1 << 20) +#define DE_DP_A_HOTPLUG (1 << 19) +#define DE_GSE (1 << 18) +#define DE_PIPEB_VBLANK (1 << 15) +#define DE_PIPEB_EVEN_FIELD (1 << 14) +#define DE_PIPEB_ODD_FIELD (1 << 13) +#define DE_PIPEB_LINE_COMPARE (1 << 12) +#define DE_PIPEB_VSYNC (1 << 11) +#define DE_PIPEB_FIFO_UNDERRUN (1 << 8) +#define DE_PIPEA_VBLANK (1 << 7) +#define DE_PIPEA_EVEN_FIELD (1 << 6) +#define DE_PIPEA_ODD_FIELD (1 << 5) +#define DE_PIPEA_LINE_COMPARE (1 << 4) +#define DE_PIPEA_VSYNC (1 << 3) +#define DE_PIPEA_FIFO_UNDERRUN (1 << 0) + +#define DEISR 0x44000 +#define DEIMR 0x44004 +#define DEIIR 0x44008 +#define DEIER 0x4400c + +/* GT interrupt */ +#define GT_SYNC_STATUS (1 << 2) +#define GT_USER_INTERRUPT (1 << 0) + +#define GTISR 0x44010 +#define GTIMR 0x44014 +#define GTIIR 0x44018 +#define GTIER 0x4401c + +/* PCH */ + +/* south display engine interrupt */ +#define SDE_CRT_HOTPLUG (1 << 11) +#define SDE_PORTD_HOTPLUG (1 << 10) +#define SDE_PORTC_HOTPLUG (1 << 9) +#define SDE_PORTB_HOTPLUG (1 << 8) +#define SDE_SDVOB_HOTPLUG (1 << 6) + +#define SDEISR 0xc4000 +#define SDEIMR 0xc4004 +#define SDEIIR 0xc4008 +#define SDEIER 0xc400c + +/* digital port hotplug */ +#define PCH_PORT_HOTPLUG 0xc4030 +#define PORTD_HOTPLUG_ENABLE (1 << 20) +#define PORTD_PULSE_DURATION_2ms (0) +#define PORTD_PULSE_DURATION_4_5ms (1 << 18) +#define PORTD_PULSE_DURATION_6ms (2 << 18) +#define PORTD_PULSE_DURATION_100ms (3 << 18) +#define PORTD_HOTPLUG_NO_DETECT (0) +#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) +#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) +#define PORTC_HOTPLUG_ENABLE (1 << 12) +#define PORTC_PULSE_DURATION_2ms (0) +#define PORTC_PULSE_DURATION_4_5ms (1 << 10) +#define PORTC_PULSE_DURATION_6ms (2 << 10) +#define PORTC_PULSE_DURATION_100ms (3 << 10) +#define PORTC_HOTPLUG_NO_DETECT (0) +#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) +#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) +#define PORTB_HOTPLUG_ENABLE (1 << 4) +#define PORTB_PULSE_DURATION_2ms (0) +#define PORTB_PULSE_DURATION_4_5ms (1 << 2) +#define PORTB_PULSE_DURATION_6ms (2 << 2) +#define PORTB_PULSE_DURATION_100ms (3 << 2) +#define PORTB_HOTPLUG_NO_DETECT (0) +#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) + +#define PCH_GPIOA 0xc5010 +#define PCH_GPIOB 0xc5014 +#define PCH_GPIOC 0xc5018 +#define PCH_GPIOD 0xc501c +#define PCH_GPIOE 0xc5020 +#define PCH_GPIOF 0xc5024 + +#define PCH_DPLL_A 0xc6014 +#define PCH_DPLL_B 0xc6018 + +#define PCH_FPA0 0xc6040 +#define PCH_FPA1 0xc6044 +#define PCH_FPB0 0xc6048 +#define PCH_FPB1 0xc604c + +#define PCH_DPLL_TEST 0xc606c + +#define PCH_DREF_CONTROL 0xC6200 +#define DREF_CONTROL_MASK 0x7fc3 +#define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) +#define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) +#define DREF_CPU_SOURCE_OUTPUT_NONSPREAD (3<<13) +#define DREF_CPU_SOURCE_OUTPUT_MASK (3<<13) +#define DREF_SSC_SOURCE_DISABLE (0<<11) +#define DREF_SSC_SOURCE_ENABLE (2<<11) +#define DREF_SSC_SOURCE_MASK (2<<11) +#define DREF_NONSPREAD_SOURCE_DISABLE (0<<9) +#define DREF_NONSPREAD_CK505_ENABLE (1<<9) +#define DREF_NONSPREAD_SOURCE_ENABLE (2<<9) +#define DREF_NONSPREAD_SOURCE_MASK (2<<9) +#define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) +#define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) +#define DREF_SSC4_DOWNSPREAD (0<<6) +#define DREF_SSC4_CENTERSPREAD (1<<6) +#define DREF_SSC1_DISABLE (0<<1) +#define DREF_SSC1_ENABLE (1<<1) +#define DREF_SSC4_DISABLE (0) +#define DREF_SSC4_ENABLE (1) + +#define PCH_RAWCLK_FREQ 0xc6204 +#define FDL_TP1_TIMER_SHIFT 12 +#define FDL_TP1_TIMER_MASK (3<<12) +#define FDL_TP2_TIMER_SHIFT 10 +#define FDL_TP2_TIMER_MASK (3<<10) +#define RAWCLK_FREQ_MASK 0x3ff + +#define PCH_DPLL_TMR_CFG 0xc6208 + +#define PCH_SSC4_PARMS 0xc6210 +#define PCH_SSC4_AUX_PARMS 0xc6214 + +/* transcoder */ + +#define TRANS_HTOTAL_A 0xe0000 +#define TRANS_HTOTAL_SHIFT 16 +#define TRANS_HACTIVE_SHIFT 0 +#define TRANS_HBLANK_A 0xe0004 +#define TRANS_HBLANK_END_SHIFT 16 +#define TRANS_HBLANK_START_SHIFT 0 +#define TRANS_HSYNC_A 0xe0008 +#define TRANS_HSYNC_END_SHIFT 16 +#define TRANS_HSYNC_START_SHIFT 0 +#define TRANS_VTOTAL_A 0xe000c +#define TRANS_VTOTAL_SHIFT 16 +#define TRANS_VACTIVE_SHIFT 0 +#define TRANS_VBLANK_A 0xe0010 +#define TRANS_VBLANK_END_SHIFT 16 +#define TRANS_VBLANK_START_SHIFT 0 +#define TRANS_VSYNC_A 0xe0014 +#define TRANS_VSYNC_END_SHIFT 16 +#define TRANS_VSYNC_START_SHIFT 0 + +#define TRANSA_DATA_M1 0xe0030 +#define TRANSA_DATA_N1 0xe0034 +#define TRANSA_DATA_M2 0xe0038 +#define TRANSA_DATA_N2 0xe003c +#define TRANSA_DP_LINK_M1 0xe0040 +#define TRANSA_DP_LINK_N1 0xe0044 +#define TRANSA_DP_LINK_M2 0xe0048 +#define TRANSA_DP_LINK_N2 0xe004c + +#define TRANS_HTOTAL_B 0xe1000 +#define TRANS_HBLANK_B 0xe1004 +#define TRANS_HSYNC_B 0xe1008 +#define TRANS_VTOTAL_B 0xe100c +#define TRANS_VBLANK_B 0xe1010 +#define TRANS_VSYNC_B 0xe1014 + +#define TRANSB_DATA_M1 0xe1030 +#define TRANSB_DATA_N1 0xe1034 +#define TRANSB_DATA_M2 0xe1038 +#define TRANSB_DATA_N2 0xe103c +#define TRANSB_DP_LINK_M1 0xe1040 +#define TRANSB_DP_LINK_N1 0xe1044 +#define TRANSB_DP_LINK_M2 0xe1048 +#define TRANSB_DP_LINK_N2 0xe104c + +#define TRANSACONF 0xf0008 +#define TRANSBCONF 0xf1008 +#define TRANS_DISABLE (0<<31) +#define TRANS_ENABLE (1<<31) +#define TRANS_STATE_MASK (1<<30) +#define TRANS_STATE_DISABLE (0<<30) +#define TRANS_STATE_ENABLE (1<<30) +#define TRANS_FSYNC_DELAY_HB1 (0<<27) +#define TRANS_FSYNC_DELAY_HB2 (1<<27) +#define TRANS_FSYNC_DELAY_HB3 (2<<27) +#define TRANS_FSYNC_DELAY_HB4 (3<<27) +#define TRANS_DP_AUDIO_ONLY (1<<26) +#define TRANS_DP_VIDEO_AUDIO (0<<26) +#define TRANS_PROGRESSIVE (0<<21) +#define TRANS_8BPC (0<<5) +#define TRANS_10BPC (1<<5) +#define TRANS_6BPC (2<<5) +#define TRANS_12BPC (3<<5) + +#define FDI_RXA_CHICKEN 0xc200c +#define FDI_RXB_CHICKEN 0xc2010 +#define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1) + +/* CPU: FDI_TX */ +#define FDI_TXA_CTL 0x60100 +#define FDI_TXB_CTL 0x61100 +#define FDI_TX_DISABLE (0<<31) +#define FDI_TX_ENABLE (1<<31) +#define FDI_LINK_TRAIN_PATTERN_1 (0<<28) +#define FDI_LINK_TRAIN_PATTERN_2 (1<<28) +#define FDI_LINK_TRAIN_PATTERN_IDLE (2<<28) +#define FDI_LINK_TRAIN_NONE (3<<28) +#define FDI_LINK_TRAIN_VOLTAGE_0_4V (0<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_6V (1<<25) +#define FDI_LINK_TRAIN_VOLTAGE_0_8V (2<<25) +#define FDI_LINK_TRAIN_VOLTAGE_1_2V (3<<25) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_NONE (0<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_1_5X (1<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_2X (2<<22) +#define FDI_LINK_TRAIN_PRE_EMPHASIS_3X (3<<22) +#define FDI_DP_PORT_WIDTH_X1 (0<<19) +#define FDI_DP_PORT_WIDTH_X2 (1<<19) +#define FDI_DP_PORT_WIDTH_X3 (2<<19) +#define FDI_DP_PORT_WIDTH_X4 (3<<19) +#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18) +/* IGDNG: hardwired to 1 */ +#define FDI_TX_PLL_ENABLE (1<<14) +/* both Tx and Rx */ +#define FDI_SCRAMBLING_ENABLE (0<<7) +#define FDI_SCRAMBLING_DISABLE (1<<7) + +/* FDI_RX, FDI_X is hard-wired to Transcoder_X */ +#define FDI_RXA_CTL 0xf000c +#define FDI_RXB_CTL 0xf100c +#define FDI_RX_ENABLE (1<<31) +#define FDI_RX_DISABLE (0<<31) +/* train, dp width same as FDI_TX */ +#define FDI_DP_PORT_WIDTH_X8 (7<<19) +#define FDI_8BPC (0<<16) +#define FDI_10BPC (1<<16) +#define FDI_6BPC (2<<16) +#define FDI_12BPC (3<<16) +#define FDI_LINK_REVERSE_OVERWRITE (1<<15) +#define FDI_DMI_LINK_REVERSE_MASK (1<<14) +#define FDI_RX_PLL_ENABLE (1<<13) +#define FDI_FS_ERR_CORRECT_ENABLE (1<<11) +#define FDI_FE_ERR_CORRECT_ENABLE (1<<10) +#define FDI_FS_ERR_REPORT_ENABLE (1<<9) +#define FDI_FE_ERR_REPORT_ENABLE (1<<8) +#define FDI_RX_ENHANCE_FRAME_ENABLE (1<<6) +#define FDI_SEL_RAWCLK (0<<4) +#define FDI_SEL_PCDCLK (1<<4) + +#define FDI_RXA_MISC 0xf0010 +#define FDI_RXB_MISC 0xf1010 +#define FDI_RXA_TUSIZE1 0xf0030 +#define FDI_RXA_TUSIZE2 0xf0038 +#define FDI_RXB_TUSIZE1 0xf1030 +#define FDI_RXB_TUSIZE2 0xf1038 + +/* FDI_RX interrupt register format */ +#define FDI_RX_INTER_LANE_ALIGN (1<<10) +#define FDI_RX_SYMBOL_LOCK (1<<9) /* train 2 */ +#define FDI_RX_BIT_LOCK (1<<8) /* train 1 */ +#define FDI_RX_TRAIN_PATTERN_2_FAIL (1<<7) +#define FDI_RX_FS_CODE_ERR (1<<6) +#define FDI_RX_FE_CODE_ERR (1<<5) +#define FDI_RX_SYMBOL_ERR_RATE_ABOVE (1<<4) +#define FDI_RX_HDCP_LINK_FAIL (1<<3) +#define FDI_RX_PIXEL_FIFO_OVERFLOW (1<<2) +#define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) +#define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) + +#define FDI_RXA_IIR 0xf0014 +#define FDI_RXA_IMR 0xf0018 +#define FDI_RXB_IIR 0xf1014 +#define FDI_RXB_IMR 0xf1018 + +#define FDI_PLL_CTL_1 0xfe000 +#define FDI_PLL_CTL_2 0xfe004 + +/* CRT */ +#define PCH_ADPA 0xe1100 +#define ADPA_TRANS_SELECT_MASK (1<<30) +#define ADPA_TRANS_A_SELECT 0 +#define ADPA_TRANS_B_SELECT (1<<30) +#define ADPA_CRT_HOTPLUG_MASK 0x03ff0000 /* bit 25-16 */ +#define ADPA_CRT_HOTPLUG_MONITOR_NONE (0<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MASK (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_COLOR (3<<24) +#define ADPA_CRT_HOTPLUG_MONITOR_MONO (2<<24) +#define ADPA_CRT_HOTPLUG_ENABLE (1<<23) +#define ADPA_CRT_HOTPLUG_PERIOD_64 (0<<22) +#define ADPA_CRT_HOTPLUG_PERIOD_128 (1<<22) +#define ADPA_CRT_HOTPLUG_WARMUP_5MS (0<<21) +#define ADPA_CRT_HOTPLUG_WARMUP_10MS (1<<21) +#define ADPA_CRT_HOTPLUG_SAMPLE_2S (0<<20) +#define ADPA_CRT_HOTPLUG_SAMPLE_4S (1<<20) +#define ADPA_CRT_HOTPLUG_VOLTAGE_40 (0<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_50 (1<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_60 (2<<18) +#define ADPA_CRT_HOTPLUG_VOLTAGE_70 (3<<18) +#define ADPA_CRT_HOTPLUG_VOLREF_325MV (0<<17) +#define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) +#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) + +/* or SDVOB */ +#define HDMIB 0xe1140 +#define PORT_ENABLE (1 << 31) +#define TRANSCODER_A (0) +#define TRANSCODER_B (1 << 30) +#define COLOR_FORMAT_8bpc (0) +#define COLOR_FORMAT_12bpc (3 << 26) +#define SDVOB_HOTPLUG_ENABLE (1 << 23) +#define SDVO_ENCODING (0) +#define TMDS_ENCODING (2 << 10) +#define NULL_PACKET_VSYNC_ENABLE (1 << 9) +#define SDVOB_BORDER_ENABLE (1 << 7) +#define AUDIO_ENABLE (1 << 6) +#define VSYNC_ACTIVE_HIGH (1 << 4) +#define HSYNC_ACTIVE_HIGH (1 << 3) +#define PORT_DETECTED (1 << 2) + +#define HDMIC 0xe1150 +#define HDMID 0xe1160 + +#define PCH_LVDS 0xe1180 +#define LVDS_DETECTED (1 << 1) + +#define BLC_PWM_CPU_CTL2 0x48250 +#define PWM_ENABLE (1 << 31) +#define PWM_PIPE_A (0 << 29) +#define PWM_PIPE_B (1 << 29) +#define BLC_PWM_CPU_CTL 0x48254 + +#define BLC_PWM_PCH_CTL1 0xc8250 +#define PWM_PCH_ENABLE (1 << 31) +#define PWM_POLARITY_ACTIVE_LOW (1 << 29) +#define PWM_POLARITY_ACTIVE_HIGH (0 << 29) +#define PWM_POLARITY_ACTIVE_LOW2 (1 << 28) +#define PWM_POLARITY_ACTIVE_HIGH2 (0 << 28) + +#define BLC_PWM_PCH_CTL2 0xc8254 + +#define PCH_PP_STATUS 0xc7200 +#define PCH_PP_CONTROL 0xc7204 +#define EDP_FORCE_VDD (1 << 3) +#define EDP_BLC_ENABLE (1 << 2) +#define PANEL_POWER_RESET (1 << 1) +#define PANEL_POWER_OFF (0 << 0) +#define PANEL_POWER_ON (1 << 0) +#define PCH_PP_ON_DELAYS 0xc7208 +#define EDP_PANEL (1 << 30) +#define PCH_PP_OFF_DELAYS 0xc720c +#define PCH_PP_DIVISOR 0xc7210 + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index ce8a21344a7..a98e2831ed3 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -295,6 +295,16 @@ int i915_save_state(struct drm_device *dev) i915_save_palette(dev, PIPE_B); dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); + /* Cursor state */ + dev_priv->saveCURACNTR = I915_READ(CURACNTR); + dev_priv->saveCURAPOS = I915_READ(CURAPOS); + dev_priv->saveCURABASE = I915_READ(CURABASE); + dev_priv->saveCURBCNTR = I915_READ(CURBCNTR); + dev_priv->saveCURBPOS = I915_READ(CURBPOS); + dev_priv->saveCURBBASE = I915_READ(CURBBASE); + if (!IS_I9XX(dev)) + dev_priv->saveCURSIZE = I915_READ(CURSIZE); + /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -480,6 +490,16 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); + /* Cursor state */ + I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); + I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); + I915_WRITE(CURABASE, dev_priv->saveCURABASE); + I915_WRITE(CURBPOS, dev_priv->saveCURBPOS); + I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR); + I915_WRITE(CURBBASE, dev_priv->saveCURBBASE); + if (!IS_I9XX(dev)) + I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); + /* CRT state */ I915_WRITE(ADPA, dev_priv->saveADPA); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 9d78cff33b2..cdd126d068a 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -30,6 +30,8 @@ #include "i915_drv.h" #include "intel_bios.h" +#define SLAVE_ADDR1 0x70 +#define SLAVE_ADDR2 0x72 static void * find_section(struct bdb_header *bdb, int section_id) @@ -122,8 +124,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, entry = &lvds_lfp_data->data[lvds_options->panel_type]; dvo_timing = &entry->dvo_timing; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); fill_detail_timing_data(panel_fixed_mode, dvo_timing); @@ -154,8 +155,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, if (!dvo_timing) return; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) return; @@ -193,6 +193,88 @@ parse_general_features(struct drm_i915_private *dev_priv, } } +static void +parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, + struct bdb_header *bdb) +{ + struct sdvo_device_mapping *p_mapping; + struct bdb_general_definitions *p_defs; + struct child_device_config *p_child; + int i, child_device_num, count; + u16 block_size, *block_ptr; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG("No general definition block is found\n"); + return; + } + /* judge whether the size of child device meets the requirements. + * If the child device size obtained from general definition block + * is different with sizeof(struct child_device_config), skip the + * parsing of sdvo device info + */ + if (p_defs->child_dev_size != sizeof(*p_child)) { + /* different child dev size . Ignore it */ + DRM_DEBUG("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_ptr = (u16 *)((char *)p_defs - 2); + block_size = *block_ptr; + /* get the number of child device */ + child_device_num = (block_size - sizeof(*p_defs)) / + sizeof(*p_child); + count = 0; + for (i = 0; i < child_device_num; i++) { + p_child = &(p_defs->devices[i]); + if (!p_child->device_type) { + /* skip the device block if device type is invalid */ + continue; + } + if (p_child->slave_addr != SLAVE_ADDR1 && + p_child->slave_addr != SLAVE_ADDR2) { + /* + * If the slave address is neither 0x70 nor 0x72, + * it is not a SDVO device. Skip it. + */ + continue; + } + if (p_child->dvo_port != DEVICE_PORT_DVOB && + p_child->dvo_port != DEVICE_PORT_DVOC) { + /* skip the incorrect SDVO port */ + DRM_DEBUG("Incorrect SDVO port. Skip it \n"); + continue; + } + DRM_DEBUG("the SDVO device with slave addr %2x is found on " + "%s port\n", + p_child->slave_addr, + (p_child->dvo_port == DEVICE_PORT_DVOB) ? + "SDVOB" : "SDVOC"); + p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); + if (!p_mapping->initialized) { + p_mapping->dvo_port = p_child->dvo_port; + p_mapping->slave_addr = p_child->slave_addr; + p_mapping->dvo_wiring = p_child->dvo_wiring; + p_mapping->initialized = 1; + } else { + DRM_DEBUG("Maybe one SDVO port is shared by " + "two SDVO device.\n"); + } + if (p_child->slave2_addr) { + /* Maybe this is a SDVO device with multiple inputs */ + /* And the mapping info is not added */ + DRM_DEBUG("there exists the slave2_addr. Maybe this " + "is a SDVO device with multiple inputs.\n"); + } + count++; + } + + if (!count) { + /* No SDVO device info is found */ + DRM_DEBUG("No SDVO device info is found in VBT\n"); + } + return; +} /** * intel_init_bios - initialize VBIOS settings & find VBT * @dev: DRM device @@ -242,7 +324,7 @@ intel_init_bios(struct drm_device *dev) parse_general_features(dev_priv, bdb); parse_lfp_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); - + parse_sdvo_device_mapping(dev_priv, bdb); pci_unmap_rom(pdev, bios); return 0; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 8ca2cde1580..fe72e1c225d 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -135,6 +135,86 @@ struct bdb_general_features { u8 rsvd11:6; /* finish byte */ } __attribute__((packed)); +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +struct child_device_config { + u16 handle; + u16 device_type; + u8 device_id[10]; /* See DEVICE_TYPE_* above */ + u16 addin_offset; + u8 dvo_port; /* See Device_PORT_* above */ + u8 i2c_pin; + u8 slave_addr; + u8 ddc_pin; + u16 edid_ptr; + u8 dvo_cfg; /* See DEVICE_CFG_* above */ + u8 dvo2_port; + u8 i2c2_pin; + u8 slave2_addr; + u8 ddc2_pin; + u8 capabilities; + u8 dvo_wiring;/* See DEVICE_WIRE_* above */ + u8 dvo2_wiring; + u16 extended_type; + u8 dvo_function; +} __attribute__((packed)); + struct bdb_general_definitions { /* DDC GPIO */ u8 crt_ddc_gmbus_pin; @@ -149,14 +229,19 @@ struct bdb_general_definitions { u8 boot_display[2]; u8 child_dev_size; - /* device info */ - u8 tv_or_lvds_info[33]; - u8 dev1[33]; - u8 dev2[33]; - u8 dev3[33]; - u8 dev4[33]; - /* may be another device block here on some platforms */ -}; + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * sizeof(child_device_config); + */ + struct child_device_config devices[0]; +} __attribute__((packed)); struct bdb_lvds_options { u8 panel_type; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 79acc4f4c1f..6de97fc6602 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -37,9 +37,14 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp; + u32 temp, reg; - temp = I915_READ(ADPA); + if (IS_IGDNG(dev)) + reg = PCH_ADPA; + else + reg = ADPA; + + temp = I915_READ(reg); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp |= ADPA_DAC_ENABLE; @@ -58,7 +63,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) break; } - I915_WRITE(ADPA, temp); + I915_WRITE(reg, temp); } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -101,17 +106,23 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; int dpll_md_reg; u32 adpa, dpll_md; + u32 adpa_reg; if (intel_crtc->pipe == 0) dpll_md_reg = DPLL_A_MD; else dpll_md_reg = DPLL_B_MD; + if (IS_IGDNG(dev)) + adpa_reg = PCH_ADPA; + else + adpa_reg = ADPA; + /* * Disable separate mode multiplier used when cloning SDVO to CRT * XXX this needs to be adjusted when we really are cloning */ - if (IS_I965G(dev)) { + if (IS_I965G(dev) && !IS_IGDNG(dev)) { dpll_md = I915_READ(dpll_md_reg); I915_WRITE(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); @@ -125,13 +136,53 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, if (intel_crtc->pipe == 0) { adpa |= ADPA_PIPE_A_SELECT; - I915_WRITE(BCLRPAT_A, 0); + if (!IS_IGDNG(dev)) + I915_WRITE(BCLRPAT_A, 0); } else { adpa |= ADPA_PIPE_B_SELECT; - I915_WRITE(BCLRPAT_B, 0); + if (!IS_IGDNG(dev)) + I915_WRITE(BCLRPAT_B, 0); } - I915_WRITE(ADPA, adpa); + I915_WRITE(adpa_reg, adpa); +} + +static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 adpa, temp; + bool ret; + + temp = adpa = I915_READ(PCH_ADPA); + + adpa &= ~ADPA_CRT_HOTPLUG_MASK; + + adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 | + ADPA_CRT_HOTPLUG_WARMUP_10MS | + ADPA_CRT_HOTPLUG_SAMPLE_4S | + ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */ + ADPA_CRT_HOTPLUG_VOLREF_325MV | + ADPA_CRT_HOTPLUG_ENABLE | + ADPA_CRT_HOTPLUG_FORCE_TRIGGER); + + DRM_DEBUG("pch crt adpa 0x%x", adpa); + I915_WRITE(PCH_ADPA, adpa); + + /* This might not be needed as not specified in spec...*/ + udelay(1000); + + /* Check the status to see if both blue and green are on now */ + adpa = I915_READ(PCH_ADPA); + if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) == + ADPA_CRT_HOTPLUG_MONITOR_COLOR) + ret = true; + else + ret = false; + + /* restore origin register */ + I915_WRITE(PCH_ADPA, temp); + return ret; } /** @@ -148,6 +199,10 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_en; int i, tries = 0; + + if (IS_IGDNG(dev)) + return intel_igdng_crt_detect_hotplug(connector); + /* * On 4 series desktop, CRT detect sequence need to be done twice * to get a reliable result. @@ -423,6 +478,7 @@ void intel_crt_init(struct drm_device *dev) { struct drm_connector *connector; struct intel_output *intel_output; + u32 i2c_reg; intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) @@ -439,7 +495,11 @@ void intel_crt_init(struct drm_device *dev) &intel_output->enc); /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); + if (IS_IGDNG(dev)) + i2c_reg = PCH_GPIOA; + else + i2c_reg = GPIOA; + intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c9d6f10ba92..3e1c7816211 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -137,6 +137,8 @@ struct intel_limit { #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7 #define INTEL_LIMIT_IGD_SDVO_DAC 8 #define INTEL_LIMIT_IGD_LVDS 9 +#define INTEL_LIMIT_IGDNG_SDVO_DAC 10 +#define INTEL_LIMIT_IGDNG_LVDS 11 /*The parameter is for SDVO on G4x platform*/ #define G4X_DOT_SDVO_MIN 25000 @@ -216,12 +218,43 @@ struct intel_limit { #define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 +/* IGDNG */ +/* as we calculate clock using (register_value + 2) for + N/M1/M2, so here the range value for them is (actual_value-2). + */ +#define IGDNG_DOT_MIN 25000 +#define IGDNG_DOT_MAX 350000 +#define IGDNG_VCO_MIN 1760000 +#define IGDNG_VCO_MAX 3510000 +#define IGDNG_N_MIN 1 +#define IGDNG_N_MAX 5 +#define IGDNG_M_MIN 79 +#define IGDNG_M_MAX 118 +#define IGDNG_M1_MIN 12 +#define IGDNG_M1_MAX 23 +#define IGDNG_M2_MIN 5 +#define IGDNG_M2_MAX 9 +#define IGDNG_P_SDVO_DAC_MIN 5 +#define IGDNG_P_SDVO_DAC_MAX 80 +#define IGDNG_P_LVDS_MIN 28 +#define IGDNG_P_LVDS_MAX 112 +#define IGDNG_P1_MIN 1 +#define IGDNG_P1_MAX 8 +#define IGDNG_P2_SDVO_DAC_SLOW 10 +#define IGDNG_P2_SDVO_DAC_FAST 5 +#define IGDNG_P2_LVDS_SLOW 14 /* single channel */ +#define IGDNG_P2_LVDS_FAST 7 /* double channel */ +#define IGDNG_P2_DOT_LIMIT 225000 /* 225Mhz */ + static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); static bool intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); +static bool +intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock); static const intel_limit_t intel_limits[] = { { /* INTEL_LIMIT_I8XX_DVO_DAC */ @@ -383,9 +416,47 @@ static const intel_limit_t intel_limits[] = { .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW }, .find_pll = intel_find_best_PLL, }, - + { /* INTEL_LIMIT_IGDNG_SDVO_DAC */ + .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, + .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, + .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, + .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, + .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, + .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, + .p = { .min = IGDNG_P_SDVO_DAC_MIN, .max = IGDNG_P_SDVO_DAC_MAX }, + .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, + .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, + .p2_slow = IGDNG_P2_SDVO_DAC_SLOW, + .p2_fast = IGDNG_P2_SDVO_DAC_FAST }, + .find_pll = intel_igdng_find_best_PLL, + }, + { /* INTEL_LIMIT_IGDNG_LVDS */ + .dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX }, + .vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX }, + .n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX }, + .m = { .min = IGDNG_M_MIN, .max = IGDNG_M_MAX }, + .m1 = { .min = IGDNG_M1_MIN, .max = IGDNG_M1_MAX }, + .m2 = { .min = IGDNG_M2_MIN, .max = IGDNG_M2_MAX }, + .p = { .min = IGDNG_P_LVDS_MIN, .max = IGDNG_P_LVDS_MAX }, + .p1 = { .min = IGDNG_P1_MIN, .max = IGDNG_P1_MAX }, + .p2 = { .dot_limit = IGDNG_P2_DOT_LIMIT, + .p2_slow = IGDNG_P2_LVDS_SLOW, + .p2_fast = IGDNG_P2_LVDS_FAST }, + .find_pll = intel_igdng_find_best_PLL, + }, }; +static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc) +{ + const intel_limit_t *limit; + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) + limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS]; + else + limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC]; + + return limit; +} + static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -418,7 +489,9 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; const intel_limit_t *limit; - if (IS_G4X(dev)) { + if (IS_IGDNG(dev)) + limit = intel_igdng_limit(crtc); + else if (IS_G4X(dev)) { limit = intel_g4x_limit(crtc); } else if (IS_I9XX(dev) && !IS_IGD(dev)) { if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) @@ -630,7 +703,64 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, } } } + return found; +} + +static bool +intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, + int target, int refclk, intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + intel_clock_t clock; + int max_n; + bool found; + int err_most = 47; + found = false; + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == + LVDS_CLKB_POWER_UP) + clock.p2 = limit->p2.p2_fast; + else + clock.p2 = limit->p2.p2_slow; + } else { + if (target < limit->p2.dot_limit) + clock.p2 = limit->p2.p2_slow; + else + clock.p2 = limit->p2.p2_fast; + } + + memset(best_clock, 0, sizeof(*best_clock)); + max_n = limit->n.max; + /* based on hardware requriment prefer smaller n to precision */ + for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { + /* based on hardware requirment prefere larger m1,m2, p1 */ + for (clock.m1 = limit->m1.max; + clock.m1 >= limit->m1.min; clock.m1--) { + for (clock.m2 = limit->m2.max; + clock.m2 >= limit->m2.min; clock.m2--) { + for (clock.p1 = limit->p1.max; + clock.p1 >= limit->p1.min; clock.p1--) { + int this_err; + intel_clock(dev, refclk, &clock); + if (!intel_PLL_is_valid(crtc, &clock)) + continue; + this_err = abs((10000 - (target*10000/clock.dot))); + if (this_err < err_most) { + *best_clock = clock; + err_most = this_err; + max_n = clock.n; + found = true; + /* found on first matching */ + goto out; + } + } + } + } + } +out: return found; } @@ -698,19 +828,31 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(intel_fb->obj, alignment); + ret = i915_gem_object_pin(obj, alignment); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; } - ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret != 0) { - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return ret; } + /* Pre-i965 needs to install a fence for tiled scan-out */ + if (!IS_I965G(dev) && + obj_priv->fence_reg == I915_FENCE_REG_NONE && + obj_priv->tiling_mode != I915_TILING_NONE) { + ret = i915_gem_object_get_fence_reg(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } + } + dspcntr = I915_READ(dspcntr_reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; @@ -730,7 +872,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, break; default: DRM_ERROR("Unknown color depth\n"); - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return -EINVAL; } @@ -785,18 +927,292 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; } +static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int plane = intel_crtc->pipe; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR; + int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR; + int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; + int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF; + int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1; + int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; + int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; + int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; + int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; + int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; + int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; + int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B; + int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B; + int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B; + int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B; + int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B; + int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B; + u32 temp; + int tries = 5, j; + /* XXX: When our outputs are all unaware of DPMS modes other than off + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. + */ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + DRM_DEBUG("crtc %d dpms on\n", pipe); + /* enable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) == 0) { + I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } -/** - * Sets the power management mode of the pipe and plane. - * - * This code should probably grow support for turning the cursor off and back - * on appropriately at the same time as we're turning the pipe off/on. - */ -static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) + /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE | + FDI_SEL_PCDCLK | + FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */ + I915_READ(fdi_rx_reg); + udelay(200); + + /* Enable CPU FDI TX PLL, always on for IGDNG */ + temp = I915_READ(fdi_tx_reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE); + I915_READ(fdi_tx_reg); + udelay(100); + } + + /* Enable CPU pipe */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) == 0) { + I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + udelay(100); + } + + /* configure and enable CPU plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) == 0) { + I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + } + + /* enable CPU FDI TX and PCH FDI RX */ + temp = I915_READ(fdi_tx_reg); + temp |= FDI_TX_ENABLE; + temp |= FDI_DP_PORT_WIDTH_X4; /* default */ + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); + + udelay(150); + + /* Train FDI. */ + /* umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + temp = I915_READ(fdi_rx_imr_reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); + udelay(150); + + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + + if ((temp & FDI_RX_BIT_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_BIT_LOCK) + break; + udelay(200); + } + if (j != tries) + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); + else + DRM_DEBUG("train 1 fail\n"); + } else { + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_BIT_LOCK); + DRM_DEBUG("train 1 ok 2!\n"); + } + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_tx_reg, temp); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_2; + I915_WRITE(fdi_rx_reg, temp); + + udelay(150); + + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + + if ((temp & FDI_RX_SYMBOL_LOCK) == 0) { + for (j = 0; j < tries; j++) { + temp = I915_READ(fdi_rx_iir_reg); + DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp); + if (temp & FDI_RX_SYMBOL_LOCK) + break; + udelay(200); + } + if (j != tries) { + I915_WRITE(fdi_rx_iir_reg, + temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG("train 2 ok 1!\n"); + } else + DRM_DEBUG("train 2 fail\n"); + } else { + I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK); + DRM_DEBUG("train 2 ok 2!\n"); + } + DRM_DEBUG("train done\n"); + + /* set transcoder timing */ + I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg)); + I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg)); + I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg)); + + I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg)); + I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg)); + I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg)); + + /* enable PCH transcoder */ + temp = I915_READ(transconf_reg); + I915_WRITE(transconf_reg, temp | TRANS_ENABLE); + I915_READ(transconf_reg); + + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0) + ; + + /* enable normal */ + + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_TX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE | + FDI_RX_ENHANCE_FRAME_ENABLE); + I915_READ(fdi_rx_reg); + + /* wait one idle pattern time */ + udelay(100); + + intel_crtc_load_lut(crtc); + + break; + case DRM_MODE_DPMS_OFF: + DRM_DEBUG("crtc %d dpms off\n", pipe); + + /* Disable the VGA plane that we never use */ + I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE); + + /* Disable display plane */ + temp = I915_READ(dspcntr_reg); + if ((temp & DISPLAY_PLANE_ENABLE) != 0) { + I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); + /* Flush the plane changes */ + I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); + I915_READ(dspbase_reg); + } + + /* disable cpu pipe, disable after all planes disabled */ + temp = I915_READ(pipeconf_reg); + if ((temp & PIPEACONF_ENABLE) != 0) { + I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); + I915_READ(pipeconf_reg); + /* wait for cpu pipe off, pipe state */ + while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) + ; + } else + DRM_DEBUG("crtc %d is disabled\n", pipe); + + /* IGDNG-A : disable cpu panel fitter ? */ + temp = I915_READ(pf_ctl_reg); + if ((temp & PF_ENABLE) != 0) { + I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE); + I915_READ(pf_ctl_reg); + } + + /* disable CPU FDI tx and PCH FDI rx */ + temp = I915_READ(fdi_tx_reg); + I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE); + I915_READ(fdi_tx_reg); + + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE); + I915_READ(fdi_rx_reg); + + /* still set train pattern 1 */ + temp = I915_READ(fdi_tx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_tx_reg, temp); + + temp = I915_READ(fdi_rx_reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(fdi_rx_reg, temp); + + /* disable PCH transcoder */ + temp = I915_READ(transconf_reg); + if ((temp & TRANS_ENABLE) != 0) { + I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE); + I915_READ(transconf_reg); + /* wait for PCH transcoder off, transcoder state */ + while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) + ; + } + + /* disable PCH DPLL */ + temp = I915_READ(pch_dpll_reg); + if ((temp & DPLL_VCO_ENABLE) != 0) { + I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE); + I915_READ(pch_dpll_reg); + } + + temp = I915_READ(fdi_rx_reg); + if ((temp & FDI_RX_PLL_ENABLE) != 0) { + temp &= ~FDI_SEL_PCDCLK; + temp &= ~FDI_RX_PLL_ENABLE; + I915_WRITE(fdi_rx_reg, temp); + I915_READ(fdi_rx_reg); + } + + /* Wait for the clocks to turn off. */ + udelay(150); + break; + } +} + +static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; - struct drm_i915_master_private *master_priv; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; @@ -805,7 +1221,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; u32 temp; - bool enabled; /* XXX: When our outputs are all unaware of DPMS modes other than off * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. @@ -890,6 +1305,26 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) udelay(150); break; } +} + +/** + * Sets the power management mode of the pipe and plane. + * + * This code should probably grow support for turning the cursor off and back + * on appropriately at the same time as we're turning the pipe off/on. + */ +static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_master_private *master_priv; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool enabled; + + if (IS_IGDNG(dev)) + igdng_crtc_dpms(crtc, mode); + else + i9xx_crtc_dpms(crtc, mode); if (!dev->primary->master) return; @@ -947,6 +1382,12 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_device *dev = crtc->dev; + if (IS_IGDNG(dev)) { + /* FDI link clock is fixed at 2.7G */ + if (mode->clock * 3 > 27000 * 4) + return MODE_CLOCK_HIGH; + } return true; } @@ -1030,6 +1471,48 @@ static int intel_panel_fitter_pipe (struct drm_device *dev) return 1; } +struct fdi_m_n { + u32 tu; + u32 gmch_m; + u32 gmch_n; + u32 link_m; + u32 link_n; +}; + +static void +fdi_reduce_ratio(u32 *num, u32 *den) +{ + while (*num > 0xffffff || *den > 0xffffff) { + *num >>= 1; + *den >>= 1; + } +} + +#define DATA_N 0x800000 +#define LINK_N 0x80000 + +static void +igdng_compute_m_n(int bytes_per_pixel, int nlanes, + int pixel_clock, int link_clock, + struct fdi_m_n *m_n) +{ + u64 temp; + + m_n->tu = 64; /* default size */ + + temp = (u64) DATA_N * pixel_clock; + temp = div_u64(temp, link_clock); + m_n->gmch_m = (temp * bytes_per_pixel) / nlanes; + m_n->gmch_n = DATA_N; + fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); + + temp = (u64) LINK_N * pixel_clock; + m_n->link_m = div_u64(temp, link_clock); + m_n->link_n = LINK_N; + fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); +} + + static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -1063,6 +1546,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, struct drm_connector *connector; const intel_limit_t *limit; int ret; + struct fdi_m_n m_n = {0}; + int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1; + int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1; + int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1; + int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1; + int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0; + int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; + int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL; + int lvds_reg = LVDS; + u32 temp; + int sdvo_pixel_multiply; drm_vblank_pre_modeset(dev, pipe); @@ -1101,6 +1595,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000); } else if (IS_I9XX(dev)) { refclk = 96000; + if (IS_IGDNG(dev)) + refclk = 120000; /* 120Mhz refclk */ } else { refclk = 48000; } @@ -1114,6 +1610,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock); if (!ok) { DRM_ERROR("Couldn't find PLL settings for mode!\n"); + drm_vblank_post_modeset(dev, pipe); return -EINVAL; } @@ -1137,12 +1634,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } } + /* FDI link */ + if (IS_IGDNG(dev)) + igdng_compute_m_n(3, 4, /* lane num 4 */ + adjusted_mode->clock, + 270000, /* lane clock */ + &m_n); + if (IS_IGD(dev)) fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; else fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - dpll = DPLL_VGA_MODE_DIS; + if (!IS_IGDNG(dev)) + dpll = DPLL_VGA_MODE_DIS; + if (IS_I9XX(dev)) { if (is_lvds) dpll |= DPLLB_MODE_LVDS; @@ -1150,17 +1656,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_MODE_DAC_SERIAL; if (is_sdvo) { dpll |= DPLL_DVO_HIGH_SPEED; - if (IS_I945G(dev) || IS_I945GM(dev)) { - int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + if (IS_I945G(dev) || IS_I945GM(dev)) dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; - } + else if (IS_IGDNG(dev)) + dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; } /* compute bitmask from p1 value */ if (IS_IGD(dev)) dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_IGD; - else + else { dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; + /* also FPA1 */ + if (IS_IGDNG(dev)) + dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT; + } switch (clock.p2) { case 5: dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; @@ -1175,7 +1686,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; break; } - if (IS_I965G(dev)) + if (IS_I965G(dev) && !IS_IGDNG(dev)) dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); } else { if (is_lvds) { @@ -1207,10 +1718,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Set up the display plane register */ dspcntr = DISPPLANE_GAMMA_ENABLE; - if (pipe == 0) - dspcntr |= DISPPLANE_SEL_PIPE_A; - else - dspcntr |= DISPPLANE_SEL_PIPE_B; + /* IGDNG's plane is forced to pipe, bit 24 is to + enable color space conversion */ + if (!IS_IGDNG(dev)) { + if (pipe == 0) + dspcntr |= DISPPLANE_SEL_PIPE_A; + else + dspcntr |= DISPPLANE_SEL_PIPE_B; + } if (pipe == 0 && !IS_I965G(dev)) { /* Enable pixel doubling when the dot clock is > 90% of the (display) @@ -1231,12 +1746,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Disable the panel fitter if it was on our pipe */ - if (intel_panel_fitter_pipe(dev) == pipe) + if (!IS_IGDNG(dev) && intel_panel_fitter_pipe(dev) == pipe) I915_WRITE(PFIT_CONTROL, 0); DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); + /* assign to IGDNG registers */ + if (IS_IGDNG(dev)) { + fp_reg = pch_fp_reg; + dpll_reg = pch_dpll_reg; + } if (dpll & DPLL_VCO_ENABLE) { I915_WRITE(fp_reg, fp); @@ -1245,13 +1765,33 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(150); } + if (IS_IGDNG(dev)) { + /* enable PCH clock reference source */ + /* XXX need to change the setting for other outputs */ + u32 temp; + temp = I915_READ(PCH_DREF_CONTROL); + temp &= ~DREF_NONSPREAD_SOURCE_MASK; + temp |= DREF_NONSPREAD_CK505_ENABLE; + temp &= ~DREF_SSC_SOURCE_MASK; + temp |= DREF_SSC_SOURCE_ENABLE; + temp &= ~DREF_SSC1_ENABLE; + /* if no eDP, disable source output to CPU */ + temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE; + I915_WRITE(PCH_DREF_CONTROL, temp); + } + /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. */ if (is_lvds) { - u32 lvds = I915_READ(LVDS); + u32 lvds; + if (IS_IGDNG(dev)) + lvds_reg = PCH_LVDS; + + lvds = I915_READ(lvds_reg); lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; /* Set the B0-B3 data pairs corresponding to whether we're going to * set the DPLLs for dual-channel mode or not. @@ -1266,8 +1806,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, * panels behave in the two modes. */ - I915_WRITE(LVDS, lvds); - I915_READ(LVDS); + I915_WRITE(lvds_reg, lvds); + I915_READ(lvds_reg); } I915_WRITE(fp_reg, fp); @@ -1276,8 +1816,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Wait for the clocks to stabilize. */ udelay(150); - if (IS_I965G(dev)) { - int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; + if (IS_I965G(dev) && !IS_IGDNG(dev)) { + sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); } else { @@ -1303,9 +1843,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* pipesrc and dspsize control the size that is scaled from, which should * always be the user's requested size. */ - I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); - I915_WRITE(dsppos_reg, 0); + if (!IS_IGDNG(dev)) { + I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | + (mode->hdisplay - 1)); + I915_WRITE(dsppos_reg, 0); + } I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); + + if (IS_IGDNG(dev)) { + I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m); + I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n); + I915_WRITE(link_m1_reg, m_n.link_m); + I915_WRITE(link_n1_reg, m_n.link_n); + + /* enable FDI RX PLL too */ + temp = I915_READ(fdi_rx_reg); + I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE); + udelay(200); + } + I915_WRITE(pipeconf_reg, pipeconf); I915_READ(pipeconf_reg); @@ -1315,12 +1871,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* Flush the plane changes */ ret = intel_pipe_set_base(crtc, x, y, old_fb); - if (ret != 0) - return ret; - drm_vblank_post_modeset(dev, pipe); - return 0; + return ret; } /** Loads the palette/gamma unit for the CRTC with the prepared values */ @@ -1336,6 +1889,11 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) if (!crtc->enabled) return; + /* use legacy palette for IGDNG */ + if (IS_IGDNG(dev)) + palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A : + LGC_PALETTE_B; + for (i = 0; i < 256; i++) { I915_WRITE(palreg + 4 * i, (intel_crtc->lut_r[i] << 16) | @@ -1464,16 +2022,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) uint32_t adder; if (x < 0) { - temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); + temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; x = -x; } if (y < 0) { - temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); + temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; y = -y; } - temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); - temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); + temp |= x << CURSOR_X_SHIFT; + temp |= y << CURSOR_Y_SHIFT; adder = intel_crtc->cursor_addr; I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); @@ -1590,6 +2148,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, } encoder->crtc = crtc; + intel_output->base.encoder = encoder; intel_output->load_detect_temp = true; intel_crtc = to_intel_crtc(crtc); @@ -1625,6 +2184,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ if (intel_output->load_detect_temp) { encoder->crtc = NULL; + intel_output->base.encoder = NULL; intel_output->load_detect_temp = false; crtc->enabled = drm_helper_crtc_in_use(crtc); drm_helper_disable_unused_functions(dev); @@ -1762,6 +2322,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (intel_crtc->mode_set.mode) + drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode); drm_crtc_cleanup(crtc); kfree(intel_crtc); } @@ -1888,7 +2450,24 @@ static void intel_setup_outputs(struct drm_device *dev) if (IS_MOBILE(dev) && !IS_I830(dev)) intel_lvds_init(dev); - if (IS_I9XX(dev)) { + if (IS_IGDNG(dev)) { + int found; + + if (I915_READ(HDMIB) & PORT_DETECTED) { + /* check SDVOB */ + /* found = intel_sdvo_init(dev, HDMIB); */ + found = 0; + if (!found) + intel_hdmi_init(dev, HDMIB); + } + + if (I915_READ(HDMIC) & PORT_DETECTED) + intel_hdmi_init(dev, HDMIC); + + if (I915_READ(HDMID) & PORT_DETECTED) + intel_hdmi_init(dev, HDMID); + + } else if (IS_I9XX(dev)) { int found; u32 reg; @@ -1912,7 +2491,7 @@ static void intel_setup_outputs(struct drm_device *dev) } else intel_dvo_init(dev); - if (IS_I9XX(dev) && IS_MOBILE(dev)) + if (IS_I9XX(dev) && IS_MOBILE(dev) && !IS_IGDNG(dev)) intel_tv_init(dev); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index e4652dcdd9b..1af7d68e380 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -207,7 +207,7 @@ static int intelfb_set_par(struct fb_info *info) if (var->pixclock != -1) { - DRM_ERROR("PIXEL CLCOK SET\n"); + DRM_ERROR("PIXEL CLOCK SET\n"); return -EINVAL; } else { struct drm_crtc *crtc; @@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, info->fbops = &intelfb_ops; info->fix.line_length = fb->pitch; + + /* setup aperture base/size for vesafb takeover */ + info->aperture_base = dev->mode_config.fb_base; + if (IS_I9XX(dev)) + info->aperture_size = pci_resource_len(dev->pdev, 2); + else + info->aperture_size = pci_resource_len(dev->pdev, 0); + info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; info->fix.smem_len = size; @@ -674,8 +682,12 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc * par->crtc_ids[0] = crtc->base.id; modeset->num_connectors = conn_count; - if (modeset->mode != modeset->crtc->desired_mode) - modeset->mode = modeset->crtc->desired_mode; + if (modeset->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + modeset->crtc->desired_mode); + } par->crtc_count = 1; @@ -824,8 +836,12 @@ static int intelfb_single_fb_probe(struct drm_device *dev) par->crtc_ids[crtc_count++] = crtc->base.id; modeset->num_connectors = conn_count; - if (modeset->mode != modeset->crtc->desired_mode) - modeset->mode = modeset->crtc->desired_mode; + if (modeset->crtc->desired_mode) { + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + modeset->crtc->desired_mode); + } } par->crtc_count = crtc_count; @@ -854,12 +870,22 @@ static int intelfb_single_fb_probe(struct drm_device *dev) */ void intelfb_restore(void) { - drm_crtc_helper_set_config(&kernelfb_mode); + int ret; + if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { + printk(KERN_ERR "Failed to restore crtc configuration: %d\n", + ret); + } +} + +static void intelfb_restore_work_fn(struct work_struct *ignored) +{ + intelfb_restore(); } +static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn); static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) { - intelfb_restore(); + schedule_work(&intelfb_restore_work); } static struct sysrq_key_op sysrq_intelfb_restore_op = { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 7d6bdd70532..4ea2a651b92 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -56,7 +56,8 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE | SDVO_VSYNC_ACTIVE_HIGH | - SDVO_HSYNC_ACTIVE_HIGH; + SDVO_HSYNC_ACTIVE_HIGH | + SDVO_NULL_PACKETS_DURING_VSYNC; if (hdmi_priv->has_hdmi_sink) sdvox |= SDVO_AUDIO_ENABLE; @@ -145,6 +146,22 @@ intel_hdmi_sink_detect(struct drm_connector *connector) } static enum drm_connector_status +igdng_hdmi_detect(struct drm_connector *connector) +{ + struct intel_output *intel_output = to_intel_output(connector); + struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; + + /* FIXME hotplug detect */ + + hdmi_priv->has_hdmi_sink = false; + intel_hdmi_sink_detect(connector); + if (hdmi_priv->has_hdmi_sink) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -153,6 +170,9 @@ intel_hdmi_detect(struct drm_connector *connector) struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv; u32 temp, bit; + if (IS_IGDNG(dev)) + return igdng_hdmi_detect(connector); + temp = I915_READ(PORT_HOTPLUG_EN); switch (hdmi_priv->sdvox_reg) { @@ -269,8 +289,17 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) /* Set up the DDC bus. */ if (sdvox_reg == SDVOB) intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); - else + else if (sdvox_reg == SDVOC) intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); + else if (sdvox_reg == HDMIB) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, + "HDMIB"); + else if (sdvox_reg == HDMIC) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, + "HDMIC"); + else if (sdvox_reg == HDMID) + intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, + "HDMID"); if (!intel_output->ddc_bus) goto err_connector; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 53cccfa58b9..f073ed8432e 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -37,6 +37,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#define I915_LVDS "i915_lvds" + /** * Sets the backlight level. * @@ -45,10 +47,15 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 blc_pwm_ctl; + u32 blc_pwm_ctl, reg; + + if (IS_IGDNG(dev)) + reg = BLC_PWM_CPU_CTL; + else + reg = BLC_PWM_CTL; - blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; - I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | + blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(reg, (blc_pwm_ctl | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); } @@ -58,8 +65,14 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level) static u32 intel_lvds_get_max_backlight(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + + if (IS_IGDNG(dev)) + reg = BLC_PWM_PCH_CTL2; + else + reg = BLC_PWM_CTL; - return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> + return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >> BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; } @@ -69,23 +82,31 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev) static void intel_lvds_set_power(struct drm_device *dev, bool on) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_status; + u32 pp_status, ctl_reg, status_reg; + + if (IS_IGDNG(dev)) { + ctl_reg = PCH_PP_CONTROL; + status_reg = PCH_PP_STATUS; + } else { + ctl_reg = PP_CONTROL; + status_reg = PP_STATUS; + } if (on) { - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | + I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); do { - pp_status = I915_READ(PP_STATUS); + pp_status = I915_READ(status_reg); } while ((pp_status & PP_ON) == 0); intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); } else { intel_lvds_set_backlight(dev, 0); - I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & + I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); do { - pp_status = I915_READ(PP_STATUS); + pp_status = I915_READ(status_reg); } while (pp_status & PP_ON); } } @@ -106,12 +127,28 @@ static void intel_lvds_save(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; + u32 pwm_ctl_reg; + + if (IS_IGDNG(dev)) { + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_ctl_reg = PCH_PP_CONTROL; + pp_div_reg = PCH_PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CPU_CTL; + } else { + pp_on_reg = PP_ON_DELAYS; + pp_off_reg = PP_OFF_DELAYS; + pp_ctl_reg = PP_CONTROL; + pp_div_reg = PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CTL; + } - dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); - dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); - dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + dev_priv->savePP_ON = I915_READ(pp_on_reg); + dev_priv->savePP_OFF = I915_READ(pp_off_reg); + dev_priv->savePP_CONTROL = I915_READ(pp_ctl_reg); + dev_priv->savePP_DIVISOR = I915_READ(pp_div_reg); + dev_priv->saveBLC_PWM_CTL = I915_READ(pwm_ctl_reg); dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); @@ -127,12 +164,28 @@ static void intel_lvds_restore(struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg; + u32 pwm_ctl_reg; + + if (IS_IGDNG(dev)) { + pp_on_reg = PCH_PP_ON_DELAYS; + pp_off_reg = PCH_PP_OFF_DELAYS; + pp_ctl_reg = PCH_PP_CONTROL; + pp_div_reg = PCH_PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CPU_CTL; + } else { + pp_on_reg = PP_ON_DELAYS; + pp_off_reg = PP_OFF_DELAYS; + pp_ctl_reg = PP_CONTROL; + pp_div_reg = PP_DIVISOR; + pwm_ctl_reg = BLC_PWM_CTL; + } - I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); - I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); - I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); - I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + I915_WRITE(pwm_ctl_reg, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(pp_on_reg, dev_priv->savePP_ON); + I915_WRITE(pp_off_reg, dev_priv->savePP_OFF); + I915_WRITE(pp_div_reg, dev_priv->savePP_DIVISOR); + I915_WRITE(pp_ctl_reg, dev_priv->savePP_CONTROL); if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) intel_lvds_set_power(dev, true); else @@ -216,8 +269,14 @@ static void intel_lvds_prepare(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u32 reg; + + if (IS_IGDNG(dev)) + reg = BLC_PWM_CPU_CTL; + else + reg = BLC_PWM_CTL; - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + dev_priv->saveBLC_PWM_CTL = I915_READ(reg); dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & BACKLIGHT_DUTY_CYCLE_MASK); @@ -251,6 +310,10 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder, * settings. */ + /* No panel fitting yet, fixme */ + if (IS_IGDNG(dev)) + return; + /* * Enable automatic panel scaling so that non-native modes fill the * screen. Should be enabled before the pipe is enabled, according to @@ -382,7 +445,8 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) { - DRM_DEBUG("Skipping LVDS initialization for %s\n", id->ident); + DRM_DEBUG_KMS(I915_LVDS, + "Skipping LVDS initialization for %s\n", id->ident); return 1; } @@ -420,8 +484,21 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Studio Hybrid 140g"), }, }, - - /* FIXME: add a check for the Aopen Mini PC */ + { + .callback = intel_no_lvds_dmi_callback, + .ident = "AOpen Mini PC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AOpen"), + DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Aopen i945GTt-VFA", + .matches = { + DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"), + }, + }, { } /* terminating entry */ }; @@ -442,12 +519,18 @@ void intel_lvds_init(struct drm_device *dev) struct drm_display_mode *scan; /* *modes, *bios_mode; */ struct drm_crtc *crtc; u32 lvds; - int pipe; + int pipe, gpio = GPIOC; /* Skip init on machines we know falsely report LVDS */ if (dmi_check_system(intel_no_lvds)) return; + if (IS_IGDNG(dev)) { + if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) + return; + gpio = PCH_GPIOC; + } + intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); if (!intel_output) { return; @@ -482,7 +565,7 @@ void intel_lvds_init(struct drm_device *dev) */ /* Set up the DDC bus. */ - intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); + intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C"); if (!intel_output->ddc_bus) { dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " "failed.\n"); @@ -524,6 +607,11 @@ void intel_lvds_init(struct drm_device *dev) * on. If so, assume that whatever is currently programmed is the * correct mode. */ + + /* IGDNG: FIXME if still fail, not try pipe mode now */ + if (IS_IGDNG(dev)) + goto failed; + lvds = I915_READ(LVDS); pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; crtc = intel_get_crtc_from_pipe(dev, pipe); @@ -542,11 +630,22 @@ void intel_lvds_init(struct drm_device *dev) goto failed; out: + if (IS_IGDNG(dev)) { + u32 pwm; + /* make sure PWM is enabled */ + pwm = I915_READ(BLC_PWM_CPU_CTL2); + pwm |= (PWM_ENABLE | PWM_PIPE_B); + I915_WRITE(BLC_PWM_CPU_CTL2, pwm); + + pwm = I915_READ(BLC_PWM_PCH_CTL1); + pwm |= PWM_PCH_ENABLE; + I915_WRITE(BLC_PWM_PCH_CTL1, pwm); + } drm_sysfs_connector_add(connector); return; failed: - DRM_DEBUG("No LVDS modes found, disabling.\n"); + DRM_DEBUG_KMS(I915_LVDS, "No LVDS modes found, disabling.\n"); if (intel_output->ddc_bus) intel_i2c_destroy(intel_output->ddc_bus); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3093b4d4a4d..9a00adb3a50 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -36,7 +36,7 @@ #include "intel_sdvo_regs.h" #undef SDVO_DEBUG - +#define I915_SDVO "i915_sdvo" struct intel_sdvo_priv { struct intel_i2c_chan *i2c_bus; int slaveaddr; @@ -277,20 +277,21 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; - printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + DRM_DEBUG_KMS(I915_SDVO, "%s: W: %02X ", + SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]); + DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - printk(KERN_DEBUG " "); + DRM_LOG_KMS(" "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name); + DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) - printk(KERN_DEBUG "(%02X)", cmd); - printk(KERN_DEBUG "\n"); + DRM_LOG_KMS("(%02X)", cmd); + DRM_LOG_KMS("\n"); } #else #define intel_sdvo_debug_write(o, c, a, l) @@ -329,16 +330,16 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; - printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv)); + DRM_DEBUG_KMS(I915_SDVO, "%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]); + DRM_LOG_KMS("%02X ", ((u8 *)response)[i]); for (; i < 8; i++) - printk(KERN_DEBUG " "); + DRM_LOG_KMS(" "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk(KERN_DEBUG "(%s)", cmd_status_names[status]); + DRM_LOG_KMS("(%s)", cmd_status_names[status]); else - printk(KERN_DEBUG "(??? %d)", status); - printk(KERN_DEBUG "\n"); + DRM_LOG_KMS("(??? %d)", status); + DRM_LOG_KMS("\n"); } #else #define intel_sdvo_debug_response(o, r, l, s) @@ -1742,6 +1743,43 @@ static struct i2c_algorithm intel_sdvo_i2c_bit_algo = { .master_xfer = intel_sdvo_master_xfer, }; +static u8 +intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct sdvo_device_mapping *my_mapping, *other_mapping; + + if (output_device == SDVOB) { + my_mapping = &dev_priv->sdvo_mappings[0]; + other_mapping = &dev_priv->sdvo_mappings[1]; + } else { + my_mapping = &dev_priv->sdvo_mappings[1]; + other_mapping = &dev_priv->sdvo_mappings[0]; + } + + /* If the BIOS described our SDVO device, take advantage of it. */ + if (my_mapping->slave_addr) + return my_mapping->slave_addr; + + /* If the BIOS only described a different SDVO device, use the + * address that it isn't using. + */ + if (other_mapping->slave_addr) { + if (other_mapping->slave_addr == 0x70) + return 0x72; + else + return 0x70; + } + + /* No SDVO device info is found for another DVO port, + * so use mapping assumption we had before BIOS parsing. + */ + if (output_device == SDVOB) + return 0x70; + else + return 0x72; +} + bool intel_sdvo_init(struct drm_device *dev, int output_device) { struct drm_connector *connector; @@ -1753,6 +1791,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) u8 ch[0x40]; int i; int encoder_type, output_id; + u8 slave_addr; intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); if (!intel_output) { @@ -1771,16 +1810,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) if (!i2cbus) goto err_inteloutput; + slave_addr = intel_sdvo_get_slave_addr(dev, output_device); sdvo_priv->i2c_bus = i2cbus; if (output_device == SDVOB) { output_id = 1; - sdvo_priv->i2c_bus->slave_addr = 0x38; } else { output_id = 2; - sdvo_priv->i2c_bus->slave_addr = 0x39; } - + sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1; sdvo_priv->output_device = output_device; intel_output->i2c_bus = i2cbus; intel_output->dev_priv = sdvo_priv; @@ -1788,8 +1826,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) /* Read the regs to test if we can talk to the device */ for (i = 0; i < 0x40; i++) { if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { - DRM_DEBUG("No SDVO device found on SDVO%c\n", - output_device == SDVOB ? 'B' : 'C'); + DRM_DEBUG_KMS(I915_SDVO, + "No SDVO device found on SDVO%c\n", + output_device == SDVOB ? 'B' : 'C'); goto err_i2c; } } @@ -1873,9 +1912,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv->controlled_output = 0; memcpy (bytes, &sdvo_priv->caps.output_flags, 2); - DRM_DEBUG("%s: Unknown SDVO output type (0x%02x%02x)\n", - SDVO_NAME(sdvo_priv), - bytes[0], bytes[1]); + DRM_DEBUG_KMS(I915_SDVO, + "%s: Unknown SDVO output type (0x%02x%02x)\n", + SDVO_NAME(sdvo_priv), + bytes[0], bytes[1]); encoder_type = DRM_MODE_ENCODER_NONE; connector_type = DRM_MODE_CONNECTOR_Unknown; goto err_i2c; @@ -1905,21 +1945,21 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) &sdvo_priv->pixel_clock_max); - DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " - "clock range %dMHz - %dMHz, " - "input 1: %c, input 2: %c, " - "output 1: %c, output 2: %c\n", - SDVO_NAME(sdvo_priv), - sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, - sdvo_priv->caps.device_rev_id, - sdvo_priv->pixel_clock_min / 1000, - sdvo_priv->pixel_clock_max / 1000, - (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', - (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', - /* check currently supported outputs */ - sdvo_priv->caps.output_flags & + DRM_DEBUG_KMS(I915_SDVO, "%s device VID/DID: %02X:%02X.%02X, " + "clock range %dMHz - %dMHz, " + "input 1: %c, input 2: %c, " + "output 1: %c, output 2: %c\n", + SDVO_NAME(sdvo_priv), + sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, + sdvo_priv->caps.device_rev_id, + sdvo_priv->pixel_clock_min / 1000, + sdvo_priv->pixel_clock_max / 1000, + (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', + (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', + /* check currently supported outputs */ + sdvo_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', - sdvo_priv->caps.output_flags & + sdvo_priv->caps.output_flags & (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); return true; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 98ac0546b7b..ea68992e441 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1392,6 +1392,9 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) tv_ctl &= ~TV_TEST_MODE_MASK; tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; tv_dac &= ~TVDAC_SENSE_MASK; + tv_dac &= ~DAC_A_MASK; + tv_dac &= ~DAC_B_MASK; + tv_dac &= ~DAC_C_MASK; tv_dac |= (TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL | @@ -1558,8 +1561,7 @@ intel_tv_destroy (struct drm_connector *connector) drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), - DRM_MEM_DRIVER); + kfree(intel_output); } @@ -1692,8 +1694,8 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_output = drm_calloc(1, sizeof(struct intel_output) + - sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); + intel_output = kzalloc(sizeof(struct intel_output) + + sizeof(struct intel_tv_priv), GFP_KERNEL); if (!intel_output) { return; } @@ -1727,8 +1729,8 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, - DRM_MEM_DRIVER); + tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES, + GFP_KERNEL); if (!tv_format_names) goto out; for (i = 0; i < NUM_TV_MODES; i++) |