diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
30 files changed, 3005 insertions, 2016 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3601466c550..09e0327fc6c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -326,21 +326,21 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) struct intel_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - const char *pipe = crtc->pipe ? "B" : "A"; - const char *plane = crtc->plane ? "B" : "A"; + const char pipe = pipe_name(crtc->pipe); + const char plane = plane_name(crtc->plane); struct intel_unpin_work *work; spin_lock_irqsave(&dev->event_lock, flags); work = crtc->unpin_work; if (work == NULL) { - seq_printf(m, "No flip due on pipe %s (plane %s)\n", + seq_printf(m, "No flip due on pipe %c (plane %c)\n", pipe, plane); } else { if (!work->pending) { - seq_printf(m, "Flip queued on pipe %s (plane %s)\n", + seq_printf(m, "Flip queued on pipe %c (plane %c)\n", pipe, plane); } else { - seq_printf(m, "Flip pending (waiting for vsync) on pipe %s (plane %s)\n", + seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", pipe, plane); } if (work->enable_stall_check) @@ -458,7 +458,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret, i; + int ret, i, pipe; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -471,10 +471,10 @@ static int i915_interrupt_info(struct seq_file *m, void *data) I915_READ(IIR)); seq_printf(m, "Interrupt mask: %08x\n", I915_READ(IMR)); - seq_printf(m, "Pipe A stat: %08x\n", - I915_READ(PIPEASTAT)); - seq_printf(m, "Pipe B stat: %08x\n", - I915_READ(PIPEBSTAT)); + for_each_pipe(pipe) + seq_printf(m, "Pipe %c stat: %08x\n", + pipe_name(pipe), + I915_READ(PIPESTAT(pipe))); } else { seq_printf(m, "North Display Interrupt enable: %08x\n", I915_READ(DEIER)); @@ -544,11 +544,11 @@ static int i915_hws_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - volatile u32 *hws; + const volatile u32 __iomem *hws; int i; ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; - hws = (volatile u32 *)ring->status_page.page_addr; + hws = (volatile u32 __iomem *)ring->status_page.page_addr; if (hws == NULL) return 0; @@ -615,7 +615,7 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) if (!ring->obj) { seq_printf(m, "No ringbuffer setup\n"); } else { - u8 *virt = ring->virtual_start; + const u8 __iomem *virt = ring->virtual_start; uint32_t off; for (off = 0; off < ring->size; off += 4) { @@ -805,15 +805,20 @@ static int i915_error_state(struct seq_file *m, void *unused) } } - if (error->ringbuffer) { - struct drm_i915_error_object *obj = error->ringbuffer; - - seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); - offset += 4; + for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++) { + if (error->ringbuffer[i]) { + struct drm_i915_error_object *obj = error->ringbuffer[i]; + seq_printf(m, "%s --- ringbuffer = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (page = 0; page < obj->page_count; page++) { + for (elt = 0; elt < PAGE_SIZE/4; elt++) { + seq_printf(m, "%08x : %08x\n", + offset, + obj->pages[page][elt]); + offset += 4; + } } } } @@ -862,19 +867,44 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 rpstat; + u32 rpupei, rpcurup, rpprevup; + u32 rpdownei, rpcurdown, rpprevdown; int max_freq; /* RPSTAT1 is in the GT power well */ - __gen6_force_wake_get(dev_priv); + __gen6_gt_force_wake_get(dev_priv); + + rpstat = I915_READ(GEN6_RPSTAT1); + rpupei = I915_READ(GEN6_RP_CUR_UP_EI); + rpcurup = I915_READ(GEN6_RP_CUR_UP); + rpprevup = I915_READ(GEN6_RP_PREV_UP); + rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI); + rpcurdown = I915_READ(GEN6_RP_CUR_DOWN); + rpprevdown = I915_READ(GEN6_RP_PREV_DOWN); seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1)); + seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); seq_printf(m, "Render p-state ratio: %d\n", (gt_perf_status & 0xff00) >> 8); seq_printf(m, "Render p-state VID: %d\n", gt_perf_status & 0xff); seq_printf(m, "Render p-state limit: %d\n", rp_state_limits & 0xff); + seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> + GEN6_CAGF_SHIFT) * 100); + seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & + GEN6_CURICONT_MASK); + seq_printf(m, "RP CUR UP: %dus\n", rpcurup & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP PREV UP: %dus\n", rpprevup & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP CUR DOWN EI: %dus\n", rpdownei & + GEN6_CURIAVG_MASK); + seq_printf(m, "RP CUR DOWN: %dus\n", rpcurdown & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP PREV DOWN: %dus\n", rpprevdown & + GEN6_CURBSYTAVG_MASK); max_freq = (rp_state_cap & 0xff0000) >> 16; seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", @@ -888,7 +918,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", max_freq * 100); - __gen6_force_wake_put(dev_priv); + __gen6_gt_force_wake_put(dev_priv); } else { seq_printf(m, "no P-state info available\n"); } @@ -1259,7 +1289,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) } static struct drm_info_list i915_debugfs_list[] = { - {"i915_capabilities", i915_capabilities, 0, 0}, + {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, {"i915_gem_gtt", i915_gem_gtt_info, 0}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 17bd766f208..72730377a01 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -43,6 +43,17 @@ #include <linux/slab.h> #include <acpi/video.h> +static void i915_write_hws_pga(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 addr; + + addr = dev_priv->status_page_dmah->busaddr; + if (INTEL_INFO(dev)->gen >= 4) + addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); +} + /** * Sets up the hardware status page for devices that need a physical address * in the register. @@ -60,16 +71,13 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + ring->status_page.page_addr = + (void __force __iomem *)dev_priv->status_page_dmah->vaddr; - memset(ring->status_page.page_addr, 0, PAGE_SIZE); + memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & - 0xf0; + i915_write_hws_pga(dev); - I915_WRITE(HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG_DRIVER("Enabled hardware status page\n"); return 0; } @@ -216,7 +224,7 @@ static int i915_dma_resume(struct drm_device * dev) if (ring->status_page.gfx_addr != 0) intel_ring_setup_status_page(ring); else - I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + i915_write_hws_pga(dev); DRM_DEBUG_DRIVER("Enabled hardware status page\n"); @@ -771,6 +779,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_CONSTANTS: value = INTEL_INFO(dev)->gen >= 4; break; + case I915_PARAM_HAS_RELAXED_DELTA: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -859,8 +870,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, " G33 hw status page\n"); return -ENOMEM; } - ring->status_page.page_addr = dev_priv->hws_map.handle; - memset(ring->status_page.page_addr, 0, PAGE_SIZE); + ring->status_page.page_addr = + (void __force __iomem *)dev_priv->hws_map.handle; + memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", @@ -1895,6 +1907,17 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN2(dev)) dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + /* 965GM sometimes incorrectly writes to hardware status page (HWS) + * using 32bit addressing, overwriting memory if HWS is located + * above 4GB. + * + * The documentation also mentions an issue with undefined + * behaviour if any general state is accessed within a page above 4GB, + * which also needs to be handled carefully. + */ + if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); + mmio_bar = IS_GEN2(dev) ? 1 : 0; dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, 0); if (!dev_priv->regs) { @@ -2002,9 +2025,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); - dev_priv->trace_irq_seqno = 0; - ret = drm_vblank_init(dev, I915_NUM_PIPE); + if (IS_MOBILE(dev) || !IS_GEN2(dev)) + dev_priv->num_pipe = 2; + else + dev_priv->num_pipe = 1; + + ret = drm_vblank_init(dev, dev_priv->num_pipe); if (ret) goto out_gem_unload; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9ad42d58349..c34a8dd31d0 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -43,16 +43,28 @@ module_param_named(modeset, i915_modeset, int, 0400); unsigned int i915_fbpercrtc = 0; module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); +int i915_panel_ignore_lid = 0; +module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); + unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); +unsigned int i915_semaphores = 1; +module_param_named(semaphores, i915_semaphores, int, 0600); + +unsigned int i915_enable_rc6 = 0; +module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); + unsigned int i915_lvds_downclock = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); unsigned int i915_panel_use_ssc = 1; module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); -bool i915_try_reset = true; +int i915_vbt_sdvo_panel_type = -1; +module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); + +static bool i915_try_reset = true; module_param_named(reset, i915_try_reset, bool, 0600); static struct drm_driver driver; @@ -251,7 +263,7 @@ void intel_detect_pch (struct drm_device *dev) } } -void __gen6_force_wake_get(struct drm_i915_private *dev_priv) +void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { int count; @@ -267,12 +279,22 @@ void __gen6_force_wake_get(struct drm_i915_private *dev_priv) udelay(10); } -void __gen6_force_wake_put(struct drm_i915_private *dev_priv) +void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) { I915_WRITE_NOTRACE(FORCEWAKE, 0); POSTING_READ(FORCEWAKE); } +void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) +{ + int loop = 500; + u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); + while (fifo < 20 && loop--) { + udelay(10); + fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); + } +} + static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -360,7 +382,7 @@ static int i915_drm_thaw(struct drm_device *dev) /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); - if (dev_priv->renderctx && dev_priv->pwrctx) + if (IS_IRONLAKE_M(dev)) ironlake_enable_rc6(dev); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a78197d43ce..449650545bb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -49,17 +49,22 @@ enum pipe { PIPE_A = 0, PIPE_B, + PIPE_C, + I915_MAX_PIPES }; +#define pipe_name(p) ((p) + 'A') enum plane { PLANE_A = 0, PLANE_B, + PLANE_C, }; - -#define I915_NUM_PIPE 2 +#define plane_name(p) ((p) + 'A') #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) +#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) + /* Interface history: * * 1.1: Original. @@ -75,10 +80,7 @@ enum plane { #define DRIVER_PATCHLEVEL 0 #define WATCH_COHERENCY 0 -#define WATCH_EXEC 0 -#define WATCH_RELOC 0 #define WATCH_LISTS 0 -#define WATCH_PWRITE 0 #define I915_GEM_PHYS_CURSOR_0 1 #define I915_GEM_PHYS_CURSOR_1 2 @@ -111,6 +113,7 @@ struct intel_opregion { struct opregion_swsci *swsci; struct opregion_asle *asle; void *vbt; + u32 __iomem *lid_state; }; #define OPREGION_SIZE (8*1024) @@ -144,8 +147,7 @@ struct intel_display_error_state; struct drm_i915_error_state { u32 eir; u32 pgtbl_er; - u32 pipeastat; - u32 pipebstat; + u32 pipestat[I915_MAX_PIPES]; u32 ipeir; u32 ipehr; u32 instdone; @@ -172,7 +174,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer[I915_NUM_RINGS]; + } *ringbuffer[I915_NUM_RINGS], *batchbuffer[I915_NUM_RINGS]; struct drm_i915_error_buffer { u32 size; u32 name; @@ -200,9 +202,7 @@ struct drm_i915_display_funcs { void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); - void (*update_wm)(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size); + void (*update_wm)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -274,7 +274,6 @@ typedef struct drm_i915_private { uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; - dma_addr_t dma_status_page; uint32_t counter; drm_local_map_t hws_map; struct drm_i915_gem_object *pwrctx; @@ -289,7 +288,6 @@ typedef struct drm_i915_private { int page_flipping; atomic_t irq_received; - u32 trace_irq_seqno; /* protects the irq masks */ spinlock_t irq_lock; @@ -324,8 +322,6 @@ typedef struct drm_i915_private { int cfb_plane; int cfb_y; - int irq_enabled; - struct intel_opregion opregion; /* overlay */ @@ -387,7 +383,6 @@ typedef struct drm_i915_private { u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; - u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -615,6 +610,12 @@ typedef struct drm_i915_private { struct delayed_work retire_work; /** + * Are we in a non-interruptible section of code like + * modesetting? + */ + bool interruptible; + + /** * Flag if the X Server, and thus DRM, is not currently in * control of the device. * @@ -652,6 +653,7 @@ typedef struct drm_i915_private { unsigned int lvds_border_bits; /* Panel fitter placement and size for Ironlake+ */ u32 pch_pf_pos, pch_pf_size; + int panel_t3, panel_t12; struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2]; @@ -698,6 +700,8 @@ typedef struct drm_i915_private { /* list of fbdev register on this device */ struct intel_fbdev *fbdev; + + struct drm_property *broadcast_rgb_property; } drm_i915_private_t; struct drm_i915_gem_object { @@ -955,9 +959,13 @@ enum intel_chip_family { extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; +extern int i915_panel_ignore_lid; extern unsigned int i915_powersave; +extern unsigned int i915_semaphores; extern unsigned int i915_lvds_downclock; extern unsigned int i915_panel_use_ssc; +extern int i915_vbt_sdvo_panel_type; +extern unsigned int i915_enable_rc6; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); @@ -996,8 +1004,6 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); -void i915_trace_irq_get(struct drm_device *dev, u32 seqno); -extern void i915_enable_interrupt (struct drm_device *dev); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); @@ -1049,7 +1055,6 @@ extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, struct mem_block *heap); /* i915_gem.c */ -int i915_gem_check_is_wedged(struct drm_device *dev); int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_create_ioctl(struct drm_device *dev, void *data, @@ -1092,8 +1097,7 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); -int __must_check i915_gem_flush_ring(struct drm_device *dev, - struct intel_ring_buffer *ring, +int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, @@ -1108,8 +1112,7 @@ void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); -int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, u32 seqno); @@ -1131,16 +1134,14 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) } static inline u32 -i915_gem_next_request_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +i915_gem_next_request_seqno(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; return ring->outstanding_lazy_request = dev_priv->next_seqno; } int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined, - bool interruptible); + struct intel_ring_buffer *pipelined); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); @@ -1149,8 +1150,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj, uint32_t read_domains, uint32_t write_domain); -int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj); int __must_check i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); void i915_gem_do_init(struct drm_device *dev, @@ -1159,14 +1159,11 @@ void i915_gem_do_init(struct drm_device *dev, unsigned long end); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); -int __must_check i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring); -int __must_check i915_do_wait_request(struct drm_device *dev, - uint32_t seqno, - bool interruptible, - struct intel_ring_buffer *ring); +int __must_check i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + struct drm_i915_gem_request *request); +int __must_check i915_wait_request(struct intel_ring_buffer *ring, + uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int __must_check i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, @@ -1183,6 +1180,9 @@ void i915_gem_detach_phys_object(struct drm_device *dev, void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); +uint32_t +i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj); + /* i915_gem_gtt.c */ void i915_gem_restore_gtt_mappings(struct drm_device *dev); int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj); @@ -1315,7 +1315,7 @@ extern void intel_display_print_error_state(struct seq_file *m, #define __i915_read(x, y) \ static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = read##y(dev_priv->regs + reg); \ - trace_i915_reg_rw('R', reg, val, sizeof(val)); \ + trace_i915_reg_rw(false, reg, val, sizeof(val)); \ return val; \ } __i915_read(8, b) @@ -1326,7 +1326,7 @@ __i915_read(64, q) #define __i915_write(x, y) \ static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ - trace_i915_reg_rw('W', reg, val, sizeof(val)); \ + trace_i915_reg_rw(true, reg, val, sizeof(val)); \ write##y(val, dev_priv->regs + reg); \ } __i915_write(8, b) @@ -1359,62 +1359,29 @@ __i915_write(64, q) * must be set to prevent GT core from power down and stale values being * returned. */ -void __gen6_force_wake_get(struct drm_i915_private *dev_priv); -void __gen6_force_wake_put (struct drm_i915_private *dev_priv); -static inline u32 i915_safe_read(struct drm_i915_private *dev_priv, u32 reg) +void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); +void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); +void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); + +static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg) { u32 val; if (dev_priv->info->gen >= 6) { - __gen6_force_wake_get(dev_priv); + __gen6_gt_force_wake_get(dev_priv); val = I915_READ(reg); - __gen6_force_wake_put(dev_priv); + __gen6_gt_force_wake_put(dev_priv); } else val = I915_READ(reg); return val; } -static inline void -i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) +static inline void i915_gt_write(struct drm_i915_private *dev_priv, + u32 reg, u32 val) { - /* Trace down the write operation before the real write */ - trace_i915_reg_rw('W', reg, val, len); - switch (len) { - case 8: - writeq(val, dev_priv->regs + reg); - break; - case 4: - writel(val, dev_priv->regs + reg); - break; - case 2: - writew(val, dev_priv->regs + reg); - break; - case 1: - writeb(val, dev_priv->regs + reg); - break; - } + if (dev_priv->info->gen >= 6) + __gen6_gt_wait_for_fifo(dev_priv); + I915_WRITE(reg, val); } - -/** - * Reads a dword out of the status page, which is written to from the command - * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or - * MI_STORE_DATA_IMM. - * - * The following dwords have a reserved meaning: - * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes. - * 0x04: ring 0 head pointer - * 0x05: ring 1 head pointer (915-class) - * 0x06: ring 2 head pointer (915-class) - * 0x10-0x1b: Context status DWords (GM45) - * 0x1f: Last written status offset. (GM45) - * - * The area from dword 0x20 to 0x3ff is available for driver usage. - */ -#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\ - (LP_RING(dev_priv)->status_page.page_addr))[reg]) -#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) -#define I915_GEM_HWS_INDEX 0x20 -#define I915_BREADCRUMB_INDEX 0x21 - #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bc7f06b8fbc..c4c2855d002 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -75,8 +75,8 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, dev_priv->mm.object_memory -= size; } -int -i915_gem_check_is_wedged(struct drm_device *dev) +static int +i915_gem_wait_for_error(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct completion *x = &dev_priv->error_completion; @@ -90,27 +90,24 @@ i915_gem_check_is_wedged(struct drm_device *dev) if (ret) return ret; - /* Success, we reset the GPU! */ - if (!atomic_read(&dev_priv->mm.wedged)) - return 0; - - /* GPU is hung, bump the completion count to account for - * the token we just consumed so that we never hit zero and - * end up waiting upon a subsequent completion event that - * will never happen. - */ - spin_lock_irqsave(&x->wait.lock, flags); - x->done++; - spin_unlock_irqrestore(&x->wait.lock, flags); - return -EIO; + if (atomic_read(&dev_priv->mm.wedged)) { + /* GPU is hung, bump the completion count to account for + * the token we just consumed so that we never hit zero and + * end up waiting upon a subsequent completion event that + * will never happen. + */ + spin_lock_irqsave(&x->wait.lock, flags); + x->done++; + spin_unlock_irqrestore(&x->wait.lock, flags); + } + return 0; } int i915_mutex_lock_interruptible(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_gem_check_is_wedged(dev); + ret = i915_gem_wait_for_error(dev); if (ret) return ret; @@ -118,11 +115,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) if (ret) return ret; - if (atomic_read(&dev_priv->mm.wedged)) { - mutex_unlock(&dev->struct_mutex); - return -EAGAIN; - } - WARN_ON(i915_verify_lists(dev)); return 0; } @@ -543,7 +535,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -555,6 +547,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, goto out; } + trace_i915_gem_object_pread(obj, args->offset, args->size); + ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, args->size); @@ -984,7 +978,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -996,6 +990,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, goto out; } + trace_i915_gem_object_pwrite(obj, args->offset, args->size); + /* We can only do the GTT pwrite on untiled buffers, as otherwise * it would end up going through the fenced access, and we'll get * different detiling behavior between reading and writing. @@ -1078,7 +1074,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -1121,7 +1117,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -1150,7 +1146,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap *args = data; struct drm_gem_object *obj; - loff_t offset; unsigned long addr; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -1165,8 +1160,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, return -E2BIG; } - offset = args->offset; - down_write(¤t->mm->mmap_sem); addr = do_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -1211,9 +1204,13 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - /* Now bind it into the GTT if needed */ - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto out; + trace_i915_gem_object_fault(obj, page_offset, true, write); + + /* Now bind it into the GTT if needed */ if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret) @@ -1232,7 +1229,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (obj->tiling_mode == I915_TILING_NONE) ret = i915_gem_object_put_fence(obj); else - ret = i915_gem_object_get_fence(obj, NULL, true); + ret = i915_gem_object_get_fence(obj, NULL); if (ret) goto unlock; @@ -1248,12 +1245,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); unlock: mutex_unlock(&dev->struct_mutex); - +out: switch (ret) { + case -EIO: case -EAGAIN: + /* Give the error handler a chance to run and move the + * objects off the GPU active list. Next time we service the + * fault, we should be able to transition the page into the + * GTT without touching the GPU (and so avoid further + * EIO/EGAIN). If the GPU is wedged, then there is no issue + * with coherency, just lost writes. + */ set_need_resched(); case 0: case -ERESTARTSYS: + case -EINTR: return VM_FAULT_NOPAGE; case -ENOMEM: return VM_FAULT_OOM; @@ -1427,7 +1433,7 @@ i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj) * Return the required GTT alignment for an object, only taking into account * unfenced tiled surface requirements. */ -static uint32_t +uint32_t i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; @@ -1472,7 +1478,7 @@ i915_gem_mmap_gtt(struct drm_file *file, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -1712,9 +1718,8 @@ i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj) } static void -i915_gem_process_flushing_list(struct drm_device *dev, - uint32_t flush_domains, - struct intel_ring_buffer *ring) +i915_gem_process_flushing_list(struct intel_ring_buffer *ring, + uint32_t flush_domains) { struct drm_i915_gem_object *obj, *next; @@ -1727,7 +1732,7 @@ i915_gem_process_flushing_list(struct drm_device *dev, obj->base.write_domain = 0; list_del_init(&obj->gpu_write_list); i915_gem_object_move_to_active(obj, ring, - i915_gem_next_request_seqno(dev, ring)); + i915_gem_next_request_seqno(ring)); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, @@ -1737,27 +1742,22 @@ i915_gem_process_flushing_list(struct drm_device *dev, } int -i915_add_request(struct drm_device *dev, +i915_add_request(struct intel_ring_buffer *ring, struct drm_file *file, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring) + struct drm_i915_gem_request *request) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_i915_file_private *file_priv = NULL; + drm_i915_private_t *dev_priv = ring->dev->dev_private; uint32_t seqno; int was_empty; int ret; BUG_ON(request == NULL); - if (file != NULL) - file_priv = file->driver_priv; - ret = ring->add_request(ring, &seqno); if (ret) return ret; - ring->outstanding_lazy_request = false; + trace_i915_gem_request_add(ring, seqno); request->seqno = seqno; request->ring = ring; @@ -1765,7 +1765,9 @@ i915_add_request(struct drm_device *dev, was_empty = list_empty(&ring->request_list); list_add_tail(&request->list, &ring->request_list); - if (file_priv) { + if (file) { + struct drm_i915_file_private *file_priv = file->driver_priv; + spin_lock(&file_priv->mm.lock); request->file_priv = file_priv; list_add_tail(&request->client_list, @@ -1773,6 +1775,8 @@ i915_add_request(struct drm_device *dev, spin_unlock(&file_priv->mm.lock); } + ring->outstanding_lazy_request = false; + if (!dev_priv->mm.suspended) { mod_timer(&dev_priv->hangcheck_timer, jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)); @@ -1889,18 +1893,15 @@ void i915_gem_reset(struct drm_device *dev) * This function clears the request list as sequence numbers are passed. */ static void -i915_gem_retire_requests_ring(struct drm_device *dev, - struct intel_ring_buffer *ring) +i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; int i; - if (!ring->status_page.page_addr || - list_empty(&ring->request_list)) + if (list_empty(&ring->request_list)) return; - WARN_ON(i915_verify_lists(dev)); + WARN_ON(i915_verify_lists(ring->dev)); seqno = ring->get_seqno(ring); @@ -1918,7 +1919,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev, if (!i915_seqno_passed(seqno, request->seqno)) break; - trace_i915_gem_request_retire(dev, request->seqno); + trace_i915_gem_request_retire(ring, request->seqno); list_del(&request->list); i915_gem_request_remove_from_client(request); @@ -1944,13 +1945,13 @@ i915_gem_retire_requests_ring(struct drm_device *dev, i915_gem_object_move_to_inactive(obj); } - if (unlikely (dev_priv->trace_irq_seqno && - i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) { + if (unlikely(ring->trace_irq_seqno && + i915_seqno_passed(seqno, ring->trace_irq_seqno))) { ring->irq_put(ring); - dev_priv->trace_irq_seqno = 0; + ring->trace_irq_seqno = 0; } - WARN_ON(i915_verify_lists(dev)); + WARN_ON(i915_verify_lists(ring->dev)); } void @@ -1974,7 +1975,7 @@ i915_gem_retire_requests(struct drm_device *dev) } for (i = 0; i < I915_NUM_RINGS; i++) - i915_gem_retire_requests_ring(dev, &dev_priv->ring[i]); + i915_gem_retire_requests_ring(&dev_priv->ring[i]); } static void @@ -2008,11 +2009,11 @@ i915_gem_retire_work_handler(struct work_struct *work) struct drm_i915_gem_request *request; int ret; - ret = i915_gem_flush_ring(dev, ring, 0, - I915_GEM_GPU_DOMAINS); + ret = i915_gem_flush_ring(ring, + 0, I915_GEM_GPU_DOMAINS); request = kzalloc(sizeof(*request), GFP_KERNEL); if (ret || request == NULL || - i915_add_request(dev, NULL, request, ring)) + i915_add_request(ring, NULL, request)) kfree(request); } @@ -2025,18 +2026,32 @@ i915_gem_retire_work_handler(struct work_struct *work) mutex_unlock(&dev->struct_mutex); } +/** + * Waits for a sequence number to be signaled, and cleans up the + * request and object lists appropriately for that event. + */ int -i915_do_wait_request(struct drm_device *dev, uint32_t seqno, - bool interruptible, struct intel_ring_buffer *ring) +i915_wait_request(struct intel_ring_buffer *ring, + uint32_t seqno) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; u32 ier; int ret = 0; BUG_ON(seqno == 0); - if (atomic_read(&dev_priv->mm.wedged)) - return -EAGAIN; + if (atomic_read(&dev_priv->mm.wedged)) { + struct completion *x = &dev_priv->error_completion; + bool recovery_complete; + unsigned long flags; + + /* Give the error handler a chance to run. */ + spin_lock_irqsave(&x->wait.lock, flags); + recovery_complete = x->done > 0; + spin_unlock_irqrestore(&x->wait.lock, flags); + + return recovery_complete ? -EIO : -EAGAIN; + } if (seqno == ring->outstanding_lazy_request) { struct drm_i915_gem_request *request; @@ -2045,7 +2060,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, if (request == NULL) return -ENOMEM; - ret = i915_add_request(dev, NULL, request, ring); + ret = i915_add_request(ring, NULL, request); if (ret) { kfree(request); return ret; @@ -2055,22 +2070,22 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, } if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) { - if (HAS_PCH_SPLIT(dev)) + if (HAS_PCH_SPLIT(ring->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"); - i915_driver_irq_preinstall(dev); - i915_driver_irq_postinstall(dev); + i915_driver_irq_preinstall(ring->dev); + i915_driver_irq_postinstall(ring->dev); } - trace_i915_gem_request_wait_begin(dev, seqno); + trace_i915_gem_request_wait_begin(ring, seqno); ring->waiting_seqno = seqno; if (ring->irq_get(ring)) { - if (interruptible) + if (dev_priv->mm.interruptible) ret = wait_event_interruptible(ring->irq_queue, i915_seqno_passed(ring->get_seqno(ring), seqno) || atomic_read(&dev_priv->mm.wedged)); @@ -2086,7 +2101,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, ret = -EBUSY; ring->waiting_seqno = 0; - trace_i915_gem_request_wait_end(dev, seqno); + trace_i915_gem_request_wait_end(ring, seqno); } if (atomic_read(&dev_priv->mm.wedged)) ret = -EAGAIN; @@ -2102,31 +2117,18 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, * a separate wait queue to handle that. */ if (ret == 0) - i915_gem_retire_requests_ring(dev, ring); + i915_gem_retire_requests_ring(ring); return ret; } /** - * Waits for a sequence number to be signaled, and cleans up the - * request and object lists appropriately for that event. - */ -static int -i915_wait_request(struct drm_device *dev, uint32_t seqno, - struct intel_ring_buffer *ring) -{ - return i915_do_wait_request(dev, seqno, 1, ring); -} - -/** * Ensures that all rendering to the object has completed and the object is * safe to unbind from the GTT or access from the CPU. */ int -i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, - bool interruptible) +i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; int ret; /* This function only exists to support waiting for existing rendering, @@ -2138,10 +2140,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, * it. */ if (obj->active) { - ret = i915_do_wait_request(dev, - obj->last_rendering_seqno, - interruptible, - obj->ring); + ret = i915_wait_request(obj->ring, obj->last_rendering_seqno); if (ret) return ret; } @@ -2191,6 +2190,8 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) if (ret == -ERESTARTSYS) return ret; + trace_i915_gem_object_unbind(obj); + i915_gem_gtt_unbind_object(obj); i915_gem_object_put_pages_gtt(obj); @@ -2206,29 +2207,27 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) if (i915_gem_object_is_purgeable(obj)) i915_gem_object_truncate(obj); - trace_i915_gem_object_unbind(obj); - return ret; } int -i915_gem_flush_ring(struct drm_device *dev, - struct intel_ring_buffer *ring, +i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains) { int ret; + trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains); + ret = ring->flush(ring, invalidate_domains, flush_domains); if (ret) return ret; - i915_gem_process_flushing_list(dev, flush_domains, ring); + i915_gem_process_flushing_list(ring, flush_domains); return 0; } -static int i915_ring_idle(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int i915_ring_idle(struct intel_ring_buffer *ring) { int ret; @@ -2236,15 +2235,13 @@ static int i915_ring_idle(struct drm_device *dev, return 0; if (!list_empty(&ring->gpu_write_list)) { - ret = i915_gem_flush_ring(dev, ring, + ret = i915_gem_flush_ring(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; } - return i915_wait_request(dev, - i915_gem_next_request_seqno(dev, ring), - ring); + return i915_wait_request(ring, i915_gem_next_request_seqno(ring)); } int @@ -2261,7 +2258,7 @@ i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for (i = 0; i < I915_NUM_RINGS; i++) { - ret = i915_ring_idle(dev, &dev_priv->ring[i]); + ret = i915_ring_idle(&dev_priv->ring[i]); if (ret) return ret; } @@ -2445,15 +2442,13 @@ static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno) static int i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined, - bool interruptible) + struct intel_ring_buffer *pipelined) { int ret; if (obj->fenced_gpu_access) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(obj->base.dev, - obj->last_fenced_ring, + ret = i915_gem_flush_ring(obj->last_fenced_ring, 0, obj->base.write_domain); if (ret) return ret; @@ -2465,10 +2460,8 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) { if (!ring_passed_seqno(obj->last_fenced_ring, obj->last_fenced_seqno)) { - ret = i915_do_wait_request(obj->base.dev, - obj->last_fenced_seqno, - interruptible, - obj->last_fenced_ring); + ret = i915_wait_request(obj->last_fenced_ring, + obj->last_fenced_seqno); if (ret) return ret; } @@ -2494,7 +2487,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) if (obj->tiling_mode) i915_gem_release_mmap(obj); - ret = i915_gem_object_flush_fence(obj, NULL, true); + ret = i915_gem_object_flush_fence(obj, NULL); if (ret) return ret; @@ -2571,8 +2564,7 @@ i915_find_fence_reg(struct drm_device *dev, */ int i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined, - bool interruptible) + struct intel_ring_buffer *pipelined) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2594,10 +2586,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, if (reg->setup_seqno) { if (!ring_passed_seqno(obj->last_fenced_ring, reg->setup_seqno)) { - ret = i915_do_wait_request(obj->base.dev, - reg->setup_seqno, - interruptible, - obj->last_fenced_ring); + ret = i915_wait_request(obj->last_fenced_ring, + reg->setup_seqno); if (ret) return ret; } @@ -2606,15 +2596,13 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, } } else if (obj->last_fenced_ring && obj->last_fenced_ring != pipelined) { - ret = i915_gem_object_flush_fence(obj, - pipelined, - interruptible); + ret = i915_gem_object_flush_fence(obj, pipelined); if (ret) return ret; } else if (obj->tiling_changed) { if (obj->fenced_gpu_access) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(obj->base.dev, obj->ring, + ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); if (ret) return ret; @@ -2631,7 +2619,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, if (obj->tiling_changed) { if (pipelined) { reg->setup_seqno = - i915_gem_next_request_seqno(dev, pipelined); + i915_gem_next_request_seqno(pipelined); obj->last_fenced_seqno = reg->setup_seqno; obj->last_fenced_ring = pipelined; } @@ -2645,7 +2633,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, if (reg == NULL) return -ENOSPC; - ret = i915_gem_object_flush_fence(obj, pipelined, interruptible); + ret = i915_gem_object_flush_fence(obj, pipelined); if (ret) return ret; @@ -2657,9 +2645,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, if (old->tiling_mode) i915_gem_release_mmap(old); - ret = i915_gem_object_flush_fence(old, - pipelined, - interruptible); + ret = i915_gem_object_flush_fence(old, pipelined); if (ret) { drm_gem_object_unreference(&old->base); return ret; @@ -2671,7 +2657,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, old->fence_reg = I915_FENCE_REG_NONE; old->last_fenced_ring = pipelined; old->last_fenced_seqno = - pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0; + pipelined ? i915_gem_next_request_seqno(pipelined) : 0; drm_gem_object_unreference(&old->base); } else if (obj->last_fenced_seqno == 0) @@ -2683,7 +2669,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, obj->last_fenced_ring = pipelined; reg->setup_seqno = - pipelined ? i915_gem_next_request_seqno(dev, pipelined) : 0; + pipelined ? i915_gem_next_request_seqno(pipelined) : 0; obj->last_fenced_seqno = reg->setup_seqno; update: @@ -2880,7 +2866,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, obj->map_and_fenceable = mappable && fenceable; - trace_i915_gem_object_bind(obj, obj->gtt_offset, map_and_fenceable); + trace_i915_gem_object_bind(obj, map_and_fenceable); return 0; } @@ -2903,13 +2889,11 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) static int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; - if ((obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) return 0; /* Queue the GPU write cache flushing we need. */ - return i915_gem_flush_ring(dev, obj->ring, 0, obj->base.write_domain); + return i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2976,12 +2960,15 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) if (obj->gtt_space == NULL) return -EINVAL; + if (obj->base.write_domain == I915_GEM_DOMAIN_GTT) + return 0; + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; if (obj->pending_gpu_write || write) { - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; } @@ -3031,7 +3018,7 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, /* Currently, we are always called from an non-interruptible context. */ if (pipelined != obj->ring) { - ret = i915_gem_object_wait_rendering(obj, false); + ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; } @@ -3049,8 +3036,7 @@ i915_gem_object_set_to_display_plane(struct drm_i915_gem_object *obj, } int -i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, - bool interruptible) +i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj) { int ret; @@ -3058,13 +3044,12 @@ i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, return 0; if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(obj->base.dev, obj->ring, - 0, obj->base.write_domain); + ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); if (ret) return ret; } - return i915_gem_object_wait_rendering(obj, interruptible); + return i915_gem_object_wait_rendering(obj); } /** @@ -3079,11 +3064,14 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) uint32_t old_write_domain, old_read_domains; int ret; + if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) + return 0; + ret = i915_gem_object_flush_gpu_write_domain(obj); if (ret) return ret; - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; @@ -3181,7 +3169,7 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj, if (ret) return ret; - ret = i915_gem_object_wait_rendering(obj, true); + ret = i915_gem_object_wait_rendering(obj); if (ret) return ret; @@ -3252,6 +3240,9 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) u32 seqno = 0; int ret; + if (atomic_read(&dev_priv->mm.wedged)) + return -EIO; + spin_lock(&file_priv->mm.lock); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { if (time_after_eq(request->emitted_jiffies, recent_enough)) @@ -3367,7 +3358,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -3418,7 +3409,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -3455,7 +3446,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -3473,7 +3464,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * flush earlier is beneficial. */ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(dev, obj->ring, + ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); } else if (obj->ring->outstanding_lazy_request == obj->last_rendering_seqno) { @@ -3484,9 +3475,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, */ request = kzalloc(sizeof(*request), GFP_KERNEL); if (request) - ret = i915_add_request(dev, - NULL, request, - obj->ring); + ret = i915_add_request(obj->ring, NULL,request); else ret = -ENOMEM; } @@ -3496,7 +3485,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * are actually unmasked, and our working set ends up being * larger than required. */ - i915_gem_retire_requests_ring(dev, obj->ring); + i915_gem_retire_requests_ring(obj->ring); args->busy = obj->active; } @@ -3535,7 +3524,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file_priv, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -3626,6 +3615,8 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) kfree(obj->page_cpu_valid); kfree(obj->bit_17); kfree(obj); + + trace_i915_gem_object_destroy(obj); } void i915_gem_free_object(struct drm_gem_object *gem_obj) @@ -3633,8 +3624,6 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) struct drm_i915_gem_object *obj = to_intel_bo(gem_obj); struct drm_device *dev = obj->base.dev; - trace_i915_gem_object_destroy(obj); - while (obj->pin_count > 0) i915_gem_object_unpin(obj); @@ -3880,6 +3869,8 @@ i915_gem_load(struct drm_device *dev) i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); + dev_priv->mm.interruptible = true; + dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink; dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS; register_shrinker(&dev_priv->mm.inactive_shrinker); diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c index 29d014c48ca..8da1899bd24 100644 --- a/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/drivers/gpu/drm/i915/i915_gem_debug.c @@ -134,51 +134,6 @@ i915_verify_lists(struct drm_device *dev) } #endif /* WATCH_INACTIVE */ - -#if WATCH_EXEC | WATCH_PWRITE -static void -i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end, - uint32_t bias, uint32_t mark) -{ - uint32_t *mem = kmap_atomic(page, KM_USER0); - int i; - for (i = start; i < end; i += 4) - DRM_INFO("%08x: %08x%s\n", - (int) (bias + i), mem[i / 4], - (bias + i == mark) ? " ********" : ""); - kunmap_atomic(mem, KM_USER0); - /* give syslog time to catch up */ - msleep(1); -} - -void -i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, - const char *where, uint32_t mark) -{ - int page; - - DRM_INFO("%s: object at offset %08x\n", where, obj->gtt_offset); - for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) { - int page_len, chunk, chunk_len; - - page_len = len - page * PAGE_SIZE; - if (page_len > PAGE_SIZE) - page_len = PAGE_SIZE; - - for (chunk = 0; chunk < page_len; chunk += 128) { - chunk_len = page_len - chunk; - if (chunk_len > 128) - chunk_len = 128; - i915_gem_dump_page(obj->pages[page], - chunk, chunk + chunk_len, - obj->gtt_offset + - page * PAGE_SIZE, - mark); - } - } -} -#endif - #if WATCH_COHERENCY void i915_gem_object_check_coherency(struct drm_i915_gem_object *obj, int handle) diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index 3d39005540a..da05a2692a7 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -30,6 +30,7 @@ #include "drm.h" #include "i915_drv.h" #include "i915_drm.h" +#include "i915_trace.h" static bool mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) @@ -63,6 +64,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, return 0; } + trace_i915_gem_evict(dev, min_size, alignment, mappable); + /* * The goal is to evict objects and amalgamate space in LRU order. * The oldest idle objects reside on the inactive list, which is in @@ -189,6 +192,8 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only) if (lists_empty) return -ENOSPC; + trace_i915_gem_evict_everything(dev, purgeable_only); + /* Flush everything (on to the inactive lists) and evict */ ret = i915_gpu_idle(dev); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d2f445e825f..7ff7f933ddf 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -37,6 +37,7 @@ struct change_domains { uint32_t invalidate_domains; uint32_t flush_domains; uint32_t flush_rings; + uint32_t flips; }; /* @@ -190,6 +191,9 @@ i915_gem_object_set_to_gpu_domain(struct drm_i915_gem_object *obj, if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_GTT) i915_gem_release_mmap(obj); + if (obj->base.pending_write_domain) + cd->flips |= atomic_read(&obj->pending_flip); + /* The actual obj->write_domain will be updated with * pending_write_domain after we emit the accumulated flush for all * of our domain changes in execbuffers (which clears objects' @@ -282,21 +286,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, target_offset = to_intel_bo(target_obj)->gtt_offset; -#if WATCH_RELOC - DRM_INFO("%s: obj %p offset %08x target %d " - "read %08x write %08x gtt %08x " - "presumed %08x delta %08x\n", - __func__, - obj, - (int) reloc->offset, - (int) reloc->target_handle, - (int) reloc->read_domains, - (int) reloc->write_domain, - (int) target_offset, - (int) reloc->presumed_offset, - reloc->delta); -#endif - /* The target buffer should have appeared before us in the * exec_object list, so it should have a GTT space bound by now. */ @@ -365,16 +354,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, return ret; } - /* and points to somewhere within the target object. */ - if (unlikely(reloc->delta >= target_obj->size)) { - DRM_ERROR("Relocation beyond target object bounds: " - "obj %p target %d delta %d size %d.\n", - obj, reloc->target_handle, - (int) reloc->delta, - (int) target_obj->size); - return ret; - } - reloc->delta += target_offset; if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) { uint32_t page_offset = reloc->offset & ~PAGE_MASK; @@ -575,7 +554,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, if (has_fenced_gpu_access) { if (need_fence) { - ret = i915_gem_object_get_fence(obj, ring, 1); + ret = i915_gem_object_get_fence(obj, ring); if (ret) break; } else if (entry->flags & EXEC_OBJECT_NEEDS_FENCE && @@ -690,11 +669,9 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, /* reacquire the objects */ eb_reset(eb); for (i = 0; i < count; i++) { - struct drm_i915_gem_object *obj; - obj = to_intel_bo(drm_gem_object_lookup(dev, file, exec[i].handle)); - if (obj == NULL) { + if (&obj->base == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", exec[i].handle, i); ret = -ENOENT; @@ -749,8 +726,7 @@ i915_gem_execbuffer_flush(struct drm_device *dev, if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) { for (i = 0; i < I915_NUM_RINGS; i++) if (flush_rings & (1 << i)) { - ret = i915_gem_flush_ring(dev, - &dev_priv->ring[i], + ret = i915_gem_flush_ring(&dev_priv->ring[i], invalidate_domains, flush_domains); if (ret) @@ -772,9 +748,9 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, if (from == NULL || to == from) return 0; - /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */ - if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev)) - return i915_gem_object_wait_rendering(obj, true); + /* XXX gpu semaphores are implicated in various hard hangs on SNB */ + if (INTEL_INFO(obj->base.dev)->gen < 6 || !i915_semaphores) + return i915_gem_object_wait_rendering(obj); idx = intel_ring_sync_index(from, to); @@ -789,7 +765,7 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, if (request == NULL) return -ENOMEM; - ret = i915_add_request(obj->base.dev, NULL, request, from); + ret = i915_add_request(from, NULL, request); if (ret) { kfree(request); return ret; @@ -803,6 +779,39 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, } static int +i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) +{ + u32 plane, flip_mask; + int ret; + + /* Check for any pending flips. As we only maintain a flip queue depth + * of 1, we can simply insert a WAIT for the next display flip prior + * to executing the batch and avoid stalling the CPU. + */ + + for (plane = 0; flips >> plane; plane++) { + if (((flips >> plane) & 1) == 0) + continue; + + if (plane) + flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; + else + flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + } + + return 0; +} + + +static int i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, struct list_head *objects) { @@ -810,19 +819,11 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, struct change_domains cd; int ret; - cd.invalidate_domains = 0; - cd.flush_domains = 0; - cd.flush_rings = 0; + memset(&cd, 0, sizeof(cd)); list_for_each_entry(obj, objects, exec_list) i915_gem_object_set_to_gpu_domain(obj, ring, &cd); if (cd.invalidate_domains | cd.flush_domains) { -#if WATCH_EXEC - DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n", - __func__, - cd.invalidate_domains, - cd.flush_domains); -#endif ret = i915_gem_execbuffer_flush(ring->dev, cd.invalidate_domains, cd.flush_domains, @@ -831,6 +832,12 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, return ret; } + if (cd.flips) { + ret = i915_gem_execbuffer_wait_for_flips(ring, cd.flips); + if (ret) + return ret; + } + list_for_each_entry(obj, objects, exec_list) { ret = i915_gem_execbuffer_sync_rings(obj, ring); if (ret) @@ -877,47 +884,6 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } -static int -i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, - struct list_head *objects) -{ - struct drm_i915_gem_object *obj; - int flips; - - /* Check for any pending flips. As we only maintain a flip queue depth - * of 1, we can simply insert a WAIT for the next display flip prior - * to executing the batch and avoid stalling the CPU. - */ - flips = 0; - list_for_each_entry(obj, objects, exec_list) { - if (obj->base.write_domain) - flips |= atomic_read(&obj->pending_flip); - } - if (flips) { - int plane, flip_mask, ret; - - for (plane = 0; flips >> plane; plane++) { - if (((flips >> plane) & 1) == 0) - continue; - - if (plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; - - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - } - - return 0; -} - static void i915_gem_execbuffer_move_to_active(struct list_head *objects, struct intel_ring_buffer *ring, @@ -926,6 +892,10 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, struct drm_i915_gem_object *obj; list_for_each_entry(obj, objects, exec_list) { + u32 old_read = obj->base.read_domains; + u32 old_write = obj->base.write_domain; + + obj->base.read_domains = obj->base.pending_read_domains; obj->base.write_domain = obj->base.pending_write_domain; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; @@ -939,9 +909,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, intel_mark_busy(ring->dev, obj); } - trace_i915_gem_object_change_domain(obj, - obj->base.read_domains, - obj->base.write_domain); + trace_i915_gem_object_change_domain(obj, old_read, old_write); } } @@ -963,14 +931,14 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, if (INTEL_INFO(dev)->gen >= 4) invalidate |= I915_GEM_DOMAIN_SAMPLER; if (ring->flush(ring, invalidate, 0)) { - i915_gem_next_request_seqno(dev, ring); + i915_gem_next_request_seqno(ring); return; } /* Add a breadcrumb for the completion of the batch buffer */ request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL || i915_add_request(dev, file, request, ring)) { - i915_gem_next_request_seqno(dev, ring); + if (request == NULL || i915_add_request(ring, file, request)) { + i915_gem_next_request_seqno(ring); kfree(request); } } @@ -1000,10 +968,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) return ret; -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif switch (args->flags & I915_EXEC_RING_MASK) { case I915_EXEC_DEFAULT: case I915_EXEC_RENDER: @@ -1113,7 +1077,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, obj = to_intel_bo(drm_gem_object_lookup(dev, file, exec[i].handle)); - if (obj == NULL) { + if (&obj->base == NULL) { DRM_ERROR("Invalid object handle %d at index %d\n", exec[i].handle, i); /* prevent error path from reading uninitialized data */ @@ -1170,11 +1134,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - ret = i915_gem_execbuffer_wait_for_flips(ring, &objects); - if (ret) - goto err; - - seqno = i915_gem_next_request_seqno(dev, ring); + seqno = i915_gem_next_request_seqno(ring); for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) { if (seqno < ring->sync_seqno[i]) { /* The GPU can not handle its semaphore value wrapping, @@ -1189,6 +1149,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + trace_i915_gem_ring_dispatch(ring, seqno); + exec_start = batch_obj->gtt_offset + args->batch_start_offset; exec_len = args->batch_len; if (cliprects) { @@ -1245,11 +1207,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec2_list = NULL; int ret, i; -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif - if (args->buffer_count < 1) { DRM_ERROR("execbuf with %d buffers\n", args->buffer_count); return -EINVAL; @@ -1330,17 +1287,16 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec2_list = NULL; int ret; -#if WATCH_EXEC - DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", - (int) args->buffers_ptr, args->buffer_count, args->batch_len); -#endif - if (args->buffer_count < 1) { DRM_ERROR("execbuf2 with %d buffers\n", args->buffer_count); return -EINVAL; } - exec2_list = drm_malloc_ab(sizeof(*exec2_list), args->buffer_count); + exec2_list = kmalloc(sizeof(*exec2_list)*args->buffer_count, + GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); + if (exec2_list == NULL) + exec2_list = drm_malloc_ab(sizeof(*exec2_list), + args->buffer_count); if (exec2_list == NULL) { DRM_ERROR("Failed to allocate exec list for %d buffers\n", args->buffer_count); diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 22a32b9932c..281ad3d6115 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -284,14 +284,10 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, struct drm_i915_gem_set_tiling *args = data; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - int ret; - - ret = i915_gem_check_is_wedged(dev); - if (ret) - return ret; + int ret = 0; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) + if (&obj->base == NULL) return -ENOENT; if (!i915_tiling_ok(dev, @@ -349,14 +345,27 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); - obj->tiling_changed = true; - obj->tiling_mode = args->tiling_mode; - obj->stride = args->stride; + /* Rebind if we need a change of alignment */ + if (!obj->map_and_fenceable) { + u32 unfenced_alignment = + i915_gem_get_unfenced_gtt_alignment(obj); + if (obj->gtt_offset & (unfenced_alignment - 1)) + ret = i915_gem_object_unbind(obj); + } + + if (ret == 0) { + obj->tiling_changed = true; + obj->tiling_mode = args->tiling_mode; + obj->stride = args->stride; + } } + /* we have to maintain this existing ABI... */ + args->stride = obj->stride; + args->tiling_mode = obj->tiling_mode; drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } /** @@ -371,7 +380,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, struct drm_i915_gem_object *obj; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) + if (&obj->base == NULL) return -ENOENT; mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 97f946dcc1a..188b497e507 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -85,21 +85,11 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask) } } -static inline u32 -i915_pipestat(int pipe) -{ - if (pipe == 0) - return PIPEASTAT; - if (pipe == 1) - return PIPEBSTAT; - BUG(); -} - void i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { if ((dev_priv->pipestat[pipe] & mask) != mask) { - u32 reg = i915_pipestat(pipe); + u32 reg = PIPESTAT(pipe); dev_priv->pipestat[pipe] |= mask; /* Enable the interrupt, clear any pending status */ @@ -112,7 +102,7 @@ void i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask) { if ((dev_priv->pipestat[pipe] & mask) != 0) { - u32 reg = i915_pipestat(pipe); + u32 reg = PIPESTAT(pipe); dev_priv->pipestat[pipe] &= ~mask; I915_WRITE(reg, dev_priv->pipestat[pipe]); @@ -171,12 +161,12 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get vblank count for disabled " - "pipe %d\n", pipe); + "pipe %c\n", pipe_name(pipe)); return 0; } - high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + high_frame = PIPEFRAME(pipe); + low_frame = PIPEFRAMEPIXEL(pipe); /* * High & low register fields aren't synchronized, so make sure @@ -197,11 +187,11 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45; + int reg = PIPE_FRMCOUNT_GM45(pipe); if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get vblank count for disabled " - "pipe %d\n", pipe); + "pipe %c\n", pipe_name(pipe)); return 0; } @@ -219,7 +209,7 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, if (!i915_pipe_enabled(dev, pipe)) { DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " - "pipe %d\n", pipe); + "pipe %c\n", pipe_name(pipe)); return 0; } @@ -316,6 +306,8 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; + DRM_DEBUG_KMS("running encoder hotplug functions\n"); + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) if (encoder->hot_plug) encoder->hot_plug(encoder); @@ -365,7 +357,7 @@ static void notify_ring(struct drm_device *dev, return; seqno = ring->get_seqno(ring); - trace_i915_gem_request_complete(dev, seqno); + trace_i915_gem_request_complete(ring, seqno); ring->irq_seqno = seqno; wake_up_all(&ring->irq_queue); @@ -417,6 +409,7 @@ static void pch_irq_handler(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 pch_iir; + int pipe; pch_iir = I915_READ(SDEIIR); @@ -437,13 +430,11 @@ static void pch_irq_handler(struct drm_device *dev) if (pch_iir & SDE_POISON) DRM_ERROR("PCH poison interrupt\n"); - if (pch_iir & SDE_FDI_MASK) { - u32 fdia, fdib; - - fdia = I915_READ(FDI_RXA_IIR); - fdib = I915_READ(FDI_RXB_IIR); - DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib); - } + if (pch_iir & SDE_FDI_MASK) + for_each_pipe(pipe) + DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n", + pipe_name(pipe), + I915_READ(FDI_RX_IIR(pipe))); if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE)) DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n"); @@ -648,9 +639,14 @@ static void i915_error_state_free(struct drm_device *dev, struct drm_i915_error_state *error) { - i915_error_object_free(error->batchbuffer[0]); - i915_error_object_free(error->batchbuffer[1]); - i915_error_object_free(error->ringbuffer); + int i; + + for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) + i915_error_object_free(error->batchbuffer[i]); + + for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++) + i915_error_object_free(error->ringbuffer[i]); + kfree(error->active_bo); kfree(error->overlay); kfree(error); @@ -765,7 +761,7 @@ static void i915_capture_error_state(struct drm_device *dev) struct drm_i915_gem_object *obj; struct drm_i915_error_state *error; unsigned long flags; - int i; + int i, pipe; spin_lock_irqsave(&dev_priv->error_lock, flags); error = dev_priv->first_error; @@ -773,19 +769,21 @@ static void i915_capture_error_state(struct drm_device *dev) if (error) return; + /* Account for pipe specific data like PIPE*STAT */ error = kmalloc(sizeof(*error), GFP_ATOMIC); if (!error) { DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); return; } - DRM_DEBUG_DRIVER("generating error event\n"); + DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", + dev->primary->index); error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]); error->eir = I915_READ(EIR); error->pgtbl_er = I915_READ(PGTBL_ER); - error->pipeastat = I915_READ(PIPEASTAT); - error->pipebstat = I915_READ(PIPEBSTAT); + for_each_pipe(pipe) + error->pipestat[pipe] = I915_READ(PIPESTAT(pipe)); error->instpm = I915_READ(INSTPM); error->error = 0; if (INTEL_INFO(dev)->gen >= 6) { @@ -824,15 +822,16 @@ static void i915_capture_error_state(struct drm_device *dev) } i915_gem_record_fences(dev, error); - /* Record the active batchbuffers */ - for (i = 0; i < I915_NUM_RINGS; i++) + /* Record the active batch and ring buffers */ + for (i = 0; i < I915_NUM_RINGS; i++) { error->batchbuffer[i] = i915_error_first_batchbuffer(dev_priv, &dev_priv->ring[i]); - /* Record the ringbuffer */ - error->ringbuffer = i915_error_object_create(dev_priv, - dev_priv->ring[RCS].obj); + error->ringbuffer[i] = + i915_error_object_create(dev_priv, + dev_priv->ring[i].obj); + } /* Record buffers on the active and pinned lists. */ error->active_bo = NULL; @@ -905,6 +904,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 eir = I915_READ(EIR); + int pipe; if (!eir) return; @@ -953,14 +953,10 @@ static void i915_report_and_clear_eir(struct drm_device *dev) } if (eir & I915_ERROR_MEMORY_REFRESH) { - u32 pipea_stats = I915_READ(PIPEASTAT); - u32 pipeb_stats = I915_READ(PIPEBSTAT); - - printk(KERN_ERR "memory refresh error\n"); - printk(KERN_ERR "PIPEASTAT: 0x%08x\n", - pipea_stats); - printk(KERN_ERR "PIPEBSTAT: 0x%08x\n", - pipeb_stats); + printk(KERN_ERR "memory refresh error:\n"); + for_each_pipe(pipe) + printk(KERN_ERR "pipe %c stat: 0x%08x\n", + pipe_name(pipe), I915_READ(PIPESTAT(pipe))); /* pipestat has already been acked */ } if (eir & I915_ERROR_INSTRUCTION) { @@ -1074,10 +1070,10 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) /* Potential stall - if we see that the flip has happened, assume a missed interrupt */ obj = work->pending_flip_obj; if (INTEL_INFO(dev)->gen >= 4) { - int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF; + int dspsurf = DSPSURF(intel_crtc->plane); stall_detected = I915_READ(dspsurf) == obj->gtt_offset; } else { - int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR; + int dspaddr = DSPADDR(intel_crtc->plane); stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + crtc->y * crtc->fb->pitch + crtc->x * crtc->fb->bits_per_pixel/8); @@ -1097,12 +1093,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; struct drm_i915_master_private *master_priv; u32 iir, new_iir; - u32 pipea_stats, pipeb_stats; + u32 pipe_stats[I915_MAX_PIPES]; u32 vblank_status; int vblank = 0; unsigned long irqflags; int irq_received; - int ret = IRQ_NONE; + int ret = IRQ_NONE, pipe; + bool blc_event = false; atomic_inc(&dev_priv->irq_received); @@ -1125,27 +1122,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) * interrupts (for non-MSI). */ spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - pipea_stats = I915_READ(PIPEASTAT); - pipeb_stats = I915_READ(PIPEBSTAT); - if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) i915_handle_error(dev, false); - /* - * Clear the PIPE(A|B)STAT regs before the IIR - */ - if (pipea_stats & 0x8000ffff) { - if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe a underrun\n"); - I915_WRITE(PIPEASTAT, pipea_stats); - irq_received = 1; - } - - if (pipeb_stats & 0x8000ffff) { - if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS) - DRM_DEBUG_DRIVER("pipe b underrun\n"); - I915_WRITE(PIPEBSTAT, pipeb_stats); - irq_received = 1; + for_each_pipe(pipe) { + int reg = PIPESTAT(pipe); + pipe_stats[pipe] = I915_READ(reg); + + /* + * Clear the PIPE*STAT regs before the IIR + */ + if (pipe_stats[pipe] & 0x8000ffff) { + if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS) + DRM_DEBUG_DRIVER("pipe %c underrun\n", + pipe_name(pipe)); + I915_WRITE(reg, pipe_stats[pipe]); + irq_received = 1; + } } spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); @@ -1196,27 +1189,22 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip_plane(dev, 1); } - if (pipea_stats & vblank_status && - drm_handle_vblank(dev, 0)) { - vblank++; - if (!dev_priv->flip_pending_is_done) { - i915_pageflip_stall_check(dev, 0); - intel_finish_page_flip(dev, 0); + for_each_pipe(pipe) { + if (pipe_stats[pipe] & vblank_status && + drm_handle_vblank(dev, pipe)) { + vblank++; + if (!dev_priv->flip_pending_is_done) { + i915_pageflip_stall_check(dev, pipe); + intel_finish_page_flip(dev, pipe); + } } - } - if (pipeb_stats & vblank_status && - drm_handle_vblank(dev, 1)) { - vblank++; - if (!dev_priv->flip_pending_is_done) { - i915_pageflip_stall_check(dev, 1); - intel_finish_page_flip(dev, 1); - } + if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) + blc_event = true; } - if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || - (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || - (iir & I915_ASLE_INTERRUPT)) + + if (blc_event || (iir & I915_ASLE_INTERRUPT)) intel_opregion_asle_intr(dev); /* With MSI, interrupts are only generated when iir @@ -1266,16 +1254,6 @@ static int i915_emit_irq(struct drm_device * dev) return dev_priv->counter; } -void i915_trace_irq_get(struct drm_device *dev, u32 seqno) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - struct intel_ring_buffer *ring = LP_RING(dev_priv); - - if (dev_priv->trace_irq_seqno == 0 && - ring->irq_get(ring)) - dev_priv->trace_irq_seqno = seqno; -} - static int i915_wait_irq(struct drm_device * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -1375,7 +1353,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) else i915_enable_pipestat(dev_priv, pipe, PIPE_VBLANK_INTERRUPT_ENABLE); + + /* maintain vblank delivery even in deep C-states */ + if (dev_priv->info->gen == 3) + I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16); spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + return 0; } @@ -1388,6 +1371,10 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) unsigned long irqflags; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + if (dev_priv->info->gen == 3) + I915_WRITE(INSTPM, + INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS); + if (HAS_PCH_SPLIT(dev)) ironlake_disable_display_irq(dev_priv, (pipe == 0) ? DE_PIPEA_VBLANK: DE_PIPEB_VBLANK); @@ -1398,16 +1385,6 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); } -void i915_enable_interrupt (struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!HAS_PCH_SPLIT(dev)) - intel_opregion_enable_asle(dev); - dev_priv->irq_enabled = 1; -} - - /* Set the vblank monitor pipe */ int i915_vblank_pipe_set(struct drm_device *dev, void *data, @@ -1644,14 +1621,16 @@ static int ironlake_irq_postinstall(struct drm_device *dev) POSTING_READ(GTIER); if (HAS_PCH_CPT(dev)) { - hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ; + hotplug_mask = (SDE_CRT_HOTPLUG_CPT | + SDE_PORTB_HOTPLUG_CPT | + SDE_PORTC_HOTPLUG_CPT | + SDE_PORTD_HOTPLUG_CPT); } else { - hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | - SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; - hotplug_mask |= SDE_AUX_MASK | SDE_FDI_MASK | SDE_TRANS_MASK; - I915_WRITE(FDI_RXA_IMR, 0); - I915_WRITE(FDI_RXB_IMR, 0); + hotplug_mask = (SDE_CRT_HOTPLUG | + SDE_PORTB_HOTPLUG | + SDE_PORTC_HOTPLUG | + SDE_PORTD_HOTPLUG | + SDE_AUX_MASK); } dev_priv->pch_irq_mask = ~hotplug_mask; @@ -1674,6 +1653,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; atomic_set(&dev_priv->irq_received, 0); @@ -1691,8 +1671,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev) } I915_WRITE(HWSTAM, 0xeffe); - I915_WRITE(PIPEASTAT, 0); - I915_WRITE(PIPEBSTAT, 0); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0); I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); POSTING_READ(IER); @@ -1804,6 +1784,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev) void i915_driver_irq_uninstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe; if (!dev_priv) return; @@ -1821,12 +1802,13 @@ void i915_driver_irq_uninstall(struct drm_device * dev) } I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(PIPEASTAT, 0); - I915_WRITE(PIPEBSTAT, 0); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), 0); I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); - I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); - I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); + for_each_pipe(pipe) + I915_WRITE(PIPESTAT(pipe), + I915_READ(PIPESTAT(pipe)) & 0x8000ffff); I915_WRITE(IIR, I915_READ(IIR)); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5cfc68940f1..363f66ca5d3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -174,7 +174,9 @@ * address/value pairs. Don't overdue it, though, x <= 2^4 must hold! */ #define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*x-1) -#define MI_FLUSH_DW MI_INSTR(0x26, 2) /* for GEN6 */ +#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */ +#define MI_INVALIDATE_TLB (1<<18) +#define MI_INVALIDATE_BSD (1<<7) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) @@ -403,9 +405,12 @@ #define I915_ERROR_INSTRUCTION (1<<0) #define INSTPM 0x020c0 #define INSTPM_SELF_EN (1<<12) /* 915GM only */ +#define INSTPM_AGPBUSY_DIS (1<<11) /* gen3: when disabled, pending interrupts + will not assert AGPBUSY# and will only + be delivered when out of C3. */ #define ACTHD 0x020c8 #define FW_BLC 0x020d8 -#define FW_BLC2 0x020dc +#define FW_BLC2 0x020dc #define FW_BLC_SELF 0x020e0 /* 915+ only */ #define FW_BLC_SELF_EN_MASK (1<<31) #define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */ @@ -704,9 +709,9 @@ #define VGA1_PD_P1_DIV_2 (1 << 13) #define VGA1_PD_P1_SHIFT 8 #define VGA1_PD_P1_MASK (0x1f << 8) -#define DPLL_A 0x06014 -#define DPLL_B 0x06018 -#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B) +#define _DPLL_A 0x06014 +#define _DPLL_B 0x06018 +#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) @@ -777,7 +782,7 @@ #define SDVO_MULTIPLIER_MASK 0x000000ff #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define DPLL_A_MD 0x0601c /* 965+ only */ +#define _DPLL_A_MD 0x0601c /* 965+ only */ /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * @@ -814,14 +819,14 @@ */ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define DPLL_B_MD 0x06020 /* 965+ only */ -#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD) -#define FPA0 0x06040 -#define FPA1 0x06044 -#define FPB0 0x06048 -#define FPB1 0x0604c -#define FP0(pipe) _PIPE(pipe, FPA0, FPB0) -#define FP1(pipe) _PIPE(pipe, FPA1, FPB1) +#define _DPLL_B_MD 0x06020 /* 965+ only */ +#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) +#define _FPA0 0x06040 +#define _FPA1 0x06044 +#define _FPB0 0x06048 +#define _FPB1 0x0604c +#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0) +#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1) #define FP_N_DIV_MASK 0x003f0000 #define FP_N_PINEVIEW_DIV_MASK 0x00ff0000 #define FP_N_DIV_SHIFT 16 @@ -960,8 +965,9 @@ * Palette regs */ -#define PALETTE_A 0x0a000 -#define PALETTE_B 0x0a800 +#define _PALETTE_A 0x0a000 +#define _PALETTE_B 0x0a800 +#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) /* MCH MMIO space */ @@ -1265,32 +1271,32 @@ */ /* Pipe A timing regs */ -#define HTOTAL_A 0x60000 -#define HBLANK_A 0x60004 -#define HSYNC_A 0x60008 -#define VTOTAL_A 0x6000c -#define VBLANK_A 0x60010 -#define VSYNC_A 0x60014 -#define PIPEASRC 0x6001c -#define BCLRPAT_A 0x60020 +#define _HTOTAL_A 0x60000 +#define _HBLANK_A 0x60004 +#define _HSYNC_A 0x60008 +#define _VTOTAL_A 0x6000c +#define _VBLANK_A 0x60010 +#define _VSYNC_A 0x60014 +#define _PIPEASRC 0x6001c +#define _BCLRPAT_A 0x60020 /* Pipe B timing regs */ -#define HTOTAL_B 0x61000 -#define HBLANK_B 0x61004 -#define HSYNC_B 0x61008 -#define VTOTAL_B 0x6100c -#define VBLANK_B 0x61010 -#define VSYNC_B 0x61014 -#define PIPEBSRC 0x6101c -#define BCLRPAT_B 0x61020 - -#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B) -#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B) -#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B) -#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B) -#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B) -#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B) -#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B) +#define _HTOTAL_B 0x61000 +#define _HBLANK_B 0x61004 +#define _HSYNC_B 0x61008 +#define _VTOTAL_B 0x6100c +#define _VBLANK_B 0x61010 +#define _VSYNC_B 0x61014 +#define _PIPEBSRC 0x6101c +#define _BCLRPAT_B 0x61020 + +#define HTOTAL(pipe) _PIPE(pipe, _HTOTAL_A, _HTOTAL_B) +#define HBLANK(pipe) _PIPE(pipe, _HBLANK_A, _HBLANK_B) +#define HSYNC(pipe) _PIPE(pipe, _HSYNC_A, _HSYNC_B) +#define VTOTAL(pipe) _PIPE(pipe, _VTOTAL_A, _VTOTAL_B) +#define VBLANK(pipe) _PIPE(pipe, _VBLANK_A, _VBLANK_B) +#define VSYNC(pipe) _PIPE(pipe, _VSYNC_A, _VSYNC_B) +#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B) /* VGA port control */ #define ADPA 0x61100 @@ -1384,6 +1390,7 @@ #define SDVO_ENCODING_HDMI (0x2 << 10) /** Requird for HDMI operation */ #define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9) +#define SDVO_COLOR_RANGE_16_235 (1 << 8) #define SDVO_BORDER_ENABLE (1 << 7) #define SDVO_AUDIO_ENABLE (1 << 6) /** New with 965, default is to be set */ @@ -1439,8 +1446,13 @@ #define LVDS_PORT_EN (1 << 31) /* Selects pipe B for LVDS data. Must be set on pre-965. */ #define LVDS_PIPEB_SELECT (1 << 30) +#define LVDS_PIPE_MASK (1 << 30) /* LVDS dithering flag on 965/g4x platform */ #define LVDS_ENABLE_DITHER (1 << 25) +/* LVDS sync polarity flags. Set to invert (i.e. negative) */ +#define LVDS_VSYNC_POLARITY (1 << 21) +#define LVDS_HSYNC_POLARITY (1 << 20) + /* Enable border for unscaled (or aspect-scaled) display */ #define LVDS_BORDER_ENABLE (1 << 15) /* @@ -1474,6 +1486,9 @@ #define LVDS_B0B3_POWER_DOWN (0 << 2) #define LVDS_B0B3_POWER_UP (3 << 2) +#define LVDS_PIPE_ENABLED(V, P) \ + (((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN)) + /* Video Data Island Packet control */ #define VIDEO_DIP_DATA 0x61178 #define VIDEO_DIP_CTL 0x61170 @@ -1551,17 +1566,7 @@ /* Backlight control */ #define BLC_PWM_CTL 0x61254 -#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) #define BLC_PWM_CTL2 0x61250 /* 965+ only */ -#define BLM_COMBINATION_MODE (1 << 30) -/* - * This is the most significant 15 bits of the number of backlight cycles in a - * complete cycle of the modulated backlight control. - * - * The actual value is this field multiplied by two. - */ -#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) -#define BLM_LEGACY_MODE (1 << 16) /* * This is the number of cycles out of the backlight modulation cycle for which * the backlight is on. @@ -2062,6 +2067,10 @@ #define DP_PORT_EN (1 << 31) #define DP_PIPEB_SELECT (1 << 30) +#define DP_PIPE_MASK (1 << 30) + +#define DP_PIPE_ENABLED(V, P) \ + (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN)) /* Link training mode - select a suitable mode for each stage */ #define DP_LINK_TRAIN_PAT_1 (0 << 28) @@ -2204,8 +2213,8 @@ * 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 +#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) @@ -2213,8 +2222,8 @@ #define PIPE_GMCH_DATA_M_MASK (0xffffff) -#define PIPEA_GMCH_DATA_N 0x70054 -#define PIPEB_GMCH_DATA_N 0x71054 +#define _PIPEA_GMCH_DATA_N 0x70054 +#define _PIPEB_GMCH_DATA_N 0x71054 #define PIPE_GMCH_DATA_N_MASK (0xffffff) /* @@ -2228,20 +2237,25 @@ * Attributes and VB-ID. */ -#define PIPEA_DP_LINK_M 0x70060 -#define PIPEB_DP_LINK_M 0x71060 +#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 0x70064 +#define _PIPEB_DP_LINK_N 0x71064 #define PIPEA_DP_LINK_N_MASK (0xffffff) +#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M) +#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N) +#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M) +#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N) + /* Display & cursor control */ /* Pipe A */ -#define PIPEADSL 0x70000 +#define _PIPEADSL 0x70000 #define DSL_LINEMASK 0x00000fff -#define PIPEACONF 0x70008 +#define _PIPEACONF 0x70008 #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) @@ -2267,7 +2281,7 @@ #define PIPECONF_DITHER_TYPE_ST1 (1<<2) #define PIPECONF_DITHER_TYPE_ST2 (2<<2) #define PIPECONF_DITHER_TYPE_TEMP (3<<2) -#define PIPEASTAT 0x70024 +#define _PIPEASTAT 0x70024 #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) #define PIPE_CRC_DONE_ENABLE (1UL<<28) @@ -2303,10 +2317,12 @@ #define PIPE_6BPC (2 << 5) #define PIPE_12BPC (3 << 5) -#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC) -#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF) -#define PIPEDSL(pipe) _PIPE(pipe, PIPEADSL, PIPEBDSL) -#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, PIPEAFRAMEPIXEL, PIPEBFRAMEPIXEL) +#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) +#define PIPECONF(pipe) _PIPE(pipe, _PIPEACONF, _PIPEBCONF) +#define PIPEDSL(pipe) _PIPE(pipe, _PIPEADSL, _PIPEBDSL) +#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH) +#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) +#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) #define DSPARB 0x70030 #define DSPARB_CSTART_MASK (0x7f << 7) @@ -2468,20 +2484,21 @@ * } while (high1 != high2); * frame = (high1 << 8) | low1; */ -#define PIPEAFRAMEHIGH 0x70040 +#define _PIPEAFRAMEHIGH 0x70040 #define PIPE_FRAME_HIGH_MASK 0x0000ffff #define PIPE_FRAME_HIGH_SHIFT 0 -#define PIPEAFRAMEPIXEL 0x70044 +#define _PIPEAFRAMEPIXEL 0x70044 #define PIPE_FRAME_LOW_MASK 0xff000000 #define PIPE_FRAME_LOW_SHIFT 24 #define PIPE_PIXEL_MASK 0x00ffffff #define PIPE_PIXEL_SHIFT 0 /* GM45+ just has to be different */ -#define PIPEA_FRMCOUNT_GM45 0x70040 -#define PIPEA_FLIPCOUNT_GM45 0x70044 +#define _PIPEA_FRMCOUNT_GM45 0x70040 +#define _PIPEA_FLIPCOUNT_GM45 0x70044 +#define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) /* Cursor A & B regs */ -#define CURACNTR 0x70080 +#define _CURACNTR 0x70080 /* Old style CUR*CNTR flags (desktop 8xx) */ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 @@ -2502,23 +2519,23 @@ #define MCURSOR_PIPE_A 0x00 #define MCURSOR_PIPE_B (1 << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define CURABASE 0x70084 -#define CURAPOS 0x70088 +#define _CURABASE 0x70084 +#define _CURAPOS 0x70088 #define CURSOR_POS_MASK 0x007FF #define CURSOR_POS_SIGN 0x8000 #define CURSOR_X_SHIFT 0 #define CURSOR_Y_SHIFT 16 #define CURSIZE 0x700a0 -#define CURBCNTR 0x700c0 -#define CURBBASE 0x700c4 -#define CURBPOS 0x700c8 +#define _CURBCNTR 0x700c0 +#define _CURBBASE 0x700c4 +#define _CURBPOS 0x700c8 -#define CURCNTR(pipe) _PIPE(pipe, CURACNTR, CURBCNTR) -#define CURBASE(pipe) _PIPE(pipe, CURABASE, CURBBASE) -#define CURPOS(pipe) _PIPE(pipe, CURAPOS, CURBPOS) +#define CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR) +#define CURBASE(pipe) _PIPE(pipe, _CURABASE, _CURBBASE) +#define CURPOS(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS) /* Display A control */ -#define DSPACNTR 0x70180 +#define _DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) #define DISPLAY_PLANE_DISABLE 0 #define DISPPLANE_GAMMA_ENABLE (1<<30) @@ -2532,9 +2549,10 @@ #define DISPPLANE_32BPP_30BIT_NO_ALPHA (0xa<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_SHIFT 24 +#define DISPPLANE_SEL_PIPE_MASK (3<<DISPPLANE_SEL_PIPE_SHIFT) #define DISPPLANE_SEL_PIPE_A 0 -#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SEL_PIPE_B (1<<DISPPLANE_SEL_PIPE_SHIFT) #define DISPPLANE_SRC_KEY_ENABLE (1<<22) #define DISPPLANE_SRC_KEY_DISABLE 0 #define DISPPLANE_LINE_DOUBLE (1<<20) @@ -2543,20 +2561,20 @@ #define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) #define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* Ironlake */ #define DISPPLANE_TILED (1<<10) -#define DSPAADDR 0x70184 -#define DSPASTRIDE 0x70188 -#define DSPAPOS 0x7018C /* reserved */ -#define DSPASIZE 0x70190 -#define DSPASURF 0x7019C /* 965+ only */ -#define DSPATILEOFF 0x701A4 /* 965+ only */ - -#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR) -#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR) -#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE) -#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS) -#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE) -#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF) -#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF) +#define _DSPAADDR 0x70184 +#define _DSPASTRIDE 0x70188 +#define _DSPAPOS 0x7018C /* reserved */ +#define _DSPASIZE 0x70190 +#define _DSPASURF 0x7019C /* 965+ only */ +#define _DSPATILEOFF 0x701A4 /* 965+ only */ + +#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) +#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) +#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE) +#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS) +#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE) +#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) +#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) /* VBIOS flags */ #define SWF00 0x71410 @@ -2574,27 +2592,27 @@ #define SWF32 0x7241c /* Pipe B */ -#define PIPEBDSL 0x71000 -#define PIPEBCONF 0x71008 -#define PIPEBSTAT 0x71024 -#define PIPEBFRAMEHIGH 0x71040 -#define PIPEBFRAMEPIXEL 0x71044 -#define PIPEB_FRMCOUNT_GM45 0x71040 -#define PIPEB_FLIPCOUNT_GM45 0x71044 +#define _PIPEBDSL 0x71000 +#define _PIPEBCONF 0x71008 +#define _PIPEBSTAT 0x71024 +#define _PIPEBFRAMEHIGH 0x71040 +#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEB_FRMCOUNT_GM45 0x71040 +#define _PIPEB_FLIPCOUNT_GM45 0x71044 /* Display B control */ -#define DSPBCNTR 0x71180 +#define _DSPBCNTR 0x71180 #define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) -#define DSPBADDR 0x71184 -#define DSPBSTRIDE 0x71188 -#define DSPBPOS 0x7118C -#define DSPBSIZE 0x71190 -#define DSPBSURF 0x7119C -#define DSPBTILEOFF 0x711A4 +#define _DSPBADDR 0x71184 +#define _DSPBSTRIDE 0x71188 +#define _DSPBPOS 0x7118C +#define _DSPBSIZE 0x71190 +#define _DSPBSURF 0x7119C +#define _DSPBTILEOFF 0x711A4 /* VBIOS regs */ #define VGACNTRL 0x71400 @@ -2648,68 +2666,80 @@ #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff -#define PIPEA_DATA_M1 0x60030 +#define _PIPEA_DATA_M1 0x60030 #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 -#define PIPEA_DATA_N1 0x60034 +#define _PIPEA_DATA_N1 0x60034 #define PIPE_DATA_N1_OFFSET 0 -#define PIPEA_DATA_M2 0x60038 +#define _PIPEA_DATA_M2 0x60038 #define PIPE_DATA_M2_OFFSET 0 -#define PIPEA_DATA_N2 0x6003c +#define _PIPEA_DATA_N2 0x6003c #define PIPE_DATA_N2_OFFSET 0 -#define PIPEA_LINK_M1 0x60040 +#define _PIPEA_LINK_M1 0x60040 #define PIPE_LINK_M1_OFFSET 0 -#define PIPEA_LINK_N1 0x60044 +#define _PIPEA_LINK_N1 0x60044 #define PIPE_LINK_N1_OFFSET 0 -#define PIPEA_LINK_M2 0x60048 +#define _PIPEA_LINK_M2 0x60048 #define PIPE_LINK_M2_OFFSET 0 -#define PIPEA_LINK_N2 0x6004c +#define _PIPEA_LINK_N2 0x6004c #define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ -#define PIPEB_DATA_M1 0x61030 -#define PIPEB_DATA_N1 0x61034 +#define _PIPEB_DATA_M1 0x61030 +#define _PIPEB_DATA_N1 0x61034 -#define PIPEB_DATA_M2 0x61038 -#define PIPEB_DATA_N2 0x6103c +#define _PIPEB_DATA_M2 0x61038 +#define _PIPEB_DATA_N2 0x6103c -#define PIPEB_LINK_M1 0x61040 -#define PIPEB_LINK_N1 0x61044 +#define _PIPEB_LINK_M1 0x61040 +#define _PIPEB_LINK_N1 0x61044 -#define PIPEB_LINK_M2 0x61048 -#define PIPEB_LINK_N2 0x6104c +#define _PIPEB_LINK_M2 0x61048 +#define _PIPEB_LINK_N2 0x6104c -#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1) -#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1) -#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2) -#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2) -#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1) -#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1) -#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2) -#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2) +#define PIPE_DATA_M1(pipe) _PIPE(pipe, _PIPEA_DATA_M1, _PIPEB_DATA_M1) +#define PIPE_DATA_N1(pipe) _PIPE(pipe, _PIPEA_DATA_N1, _PIPEB_DATA_N1) +#define PIPE_DATA_M2(pipe) _PIPE(pipe, _PIPEA_DATA_M2, _PIPEB_DATA_M2) +#define PIPE_DATA_N2(pipe) _PIPE(pipe, _PIPEA_DATA_N2, _PIPEB_DATA_N2) +#define PIPE_LINK_M1(pipe) _PIPE(pipe, _PIPEA_LINK_M1, _PIPEB_LINK_M1) +#define PIPE_LINK_N1(pipe) _PIPE(pipe, _PIPEA_LINK_N1, _PIPEB_LINK_N1) +#define PIPE_LINK_M2(pipe) _PIPE(pipe, _PIPEA_LINK_M2, _PIPEB_LINK_M2) +#define PIPE_LINK_N2(pipe) _PIPE(pipe, _PIPEA_LINK_N2, _PIPEB_LINK_N2) /* CPU panel fitter */ -#define PFA_CTL_1 0x68080 -#define PFB_CTL_1 0x68880 +/* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ +#define _PFA_CTL_1 0x68080 +#define _PFB_CTL_1 0x68880 #define PF_ENABLE (1<<31) #define PF_FILTER_MASK (3<<23) #define PF_FILTER_PROGRAMMED (0<<23) #define PF_FILTER_MED_3x3 (1<<23) #define PF_FILTER_EDGE_ENHANCE (2<<23) #define PF_FILTER_EDGE_SOFTEN (3<<23) -#define PFA_WIN_SZ 0x68074 -#define PFB_WIN_SZ 0x68874 -#define PFA_WIN_POS 0x68070 -#define PFB_WIN_POS 0x68870 +#define _PFA_WIN_SZ 0x68074 +#define _PFB_WIN_SZ 0x68874 +#define _PFA_WIN_POS 0x68070 +#define _PFB_WIN_POS 0x68870 +#define _PFA_VSCALE 0x68084 +#define _PFB_VSCALE 0x68884 +#define _PFA_HSCALE 0x68090 +#define _PFB_HSCALE 0x68890 + +#define PF_CTL(pipe) _PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1) +#define PF_WIN_SZ(pipe) _PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ) +#define PF_WIN_POS(pipe) _PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS) +#define PF_VSCALE(pipe) _PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE) +#define PF_HSCALE(pipe) _PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE) /* legacy palette */ -#define LGC_PALETTE_A 0x4a000 -#define LGC_PALETTE_B 0x4a800 +#define _LGC_PALETTE_A 0x4a000 +#define _LGC_PALETTE_B 0x4a800 +#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) /* interrupts */ #define DE_MASTER_IRQ_CONTROL (1 << 31) @@ -2875,17 +2905,17 @@ #define PCH_GMBUS4 0xc5110 #define PCH_GMBUS5 0xc5120 -#define PCH_DPLL_A 0xc6014 -#define PCH_DPLL_B 0xc6018 -#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B) +#define _PCH_DPLL_A 0xc6014 +#define _PCH_DPLL_B 0xc6018 +#define PCH_DPLL(pipe) _PIPE(pipe, _PCH_DPLL_A, _PCH_DPLL_B) -#define PCH_FPA0 0xc6040 +#define _PCH_FPA0 0xc6040 #define FP_CB_TUNE (0x3<<22) -#define PCH_FPA1 0xc6044 -#define PCH_FPB0 0xc6048 -#define PCH_FPB1 0xc604c -#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0) -#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1) +#define _PCH_FPA1 0xc6044 +#define _PCH_FPB0 0xc6048 +#define _PCH_FPB1 0xc604c +#define PCH_FP0(pipe) _PIPE(pipe, _PCH_FPA0, _PCH_FPB0) +#define PCH_FP1(pipe) _PIPE(pipe, _PCH_FPA1, _PCH_FPB1) #define PCH_DPLL_TEST 0xc606c @@ -2904,6 +2934,7 @@ #define DREF_NONSPREAD_SOURCE_MASK (3<<9) #define DREF_SUPERSPREAD_SOURCE_DISABLE (0<<7) #define DREF_SUPERSPREAD_SOURCE_ENABLE (2<<7) +#define DREF_SUPERSPREAD_SOURCE_MASK (3<<7) #define DREF_SSC4_DOWNSPREAD (0<<6) #define DREF_SSC4_CENTERSPREAD (1<<6) #define DREF_SSC1_DISABLE (0<<1) @@ -2936,60 +2967,69 @@ /* transcoder */ -#define TRANS_HTOTAL_A 0xe0000 +#define _TRANS_HTOTAL_A 0xe0000 #define TRANS_HTOTAL_SHIFT 16 #define TRANS_HACTIVE_SHIFT 0 -#define TRANS_HBLANK_A 0xe0004 +#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_A 0xe0008 #define TRANS_HSYNC_END_SHIFT 16 #define TRANS_HSYNC_START_SHIFT 0 -#define TRANS_VTOTAL_A 0xe000c +#define _TRANS_VTOTAL_A 0xe000c #define TRANS_VTOTAL_SHIFT 16 #define TRANS_VACTIVE_SHIFT 0 -#define TRANS_VBLANK_A 0xe0010 +#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_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 TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B) -#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B) -#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B) -#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B) -#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B) -#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B) - -#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 TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF) +#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 TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B) +#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B) +#define TRANS_HSYNC(pipe) _PIPE(pipe, _TRANS_HSYNC_A, _TRANS_HSYNC_B) +#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B) +#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B) +#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B) + +#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 TRANSDATA_M1(pipe) _PIPE(pipe, _TRANSA_DATA_M1, _TRANSB_DATA_M1) +#define TRANSDATA_N1(pipe) _PIPE(pipe, _TRANSA_DATA_N1, _TRANSB_DATA_N1) +#define TRANSDATA_M2(pipe) _PIPE(pipe, _TRANSA_DATA_M2, _TRANSB_DATA_M2) +#define TRANSDATA_N2(pipe) _PIPE(pipe, _TRANSA_DATA_N2, _TRANSB_DATA_N2) +#define TRANSDPLINK_M1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M1, _TRANSB_DP_LINK_M1) +#define TRANSDPLINK_N1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N1, _TRANSB_DP_LINK_N1) +#define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2) +#define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2) + +#define _TRANSACONF 0xf0008 +#define _TRANSBCONF 0xf1008 +#define TRANSCONF(plane) _PIPE(plane, _TRANSACONF, _TRANSBCONF) #define TRANS_DISABLE (0<<31) #define TRANS_ENABLE (1<<31) #define TRANS_STATE_MASK (1<<30) @@ -3007,18 +3047,19 @@ #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) -#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, FDI_RXA_CHICKEN, FDI_RXB_CHICKEN) +#define _FDI_RXA_CHICKEN 0xc200c +#define _FDI_RXB_CHICKEN 0xc2010 +#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) +#define FDI_RX_PHASE_SYNC_POINTER_EN (1<<0) +#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) #define SOUTH_DSPCLK_GATE_D 0xc2020 #define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) /* CPU: FDI_TX */ -#define FDI_TXA_CTL 0x60100 -#define FDI_TXB_CTL 0x61100 -#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL) +#define _FDI_TXA_CTL 0x60100 +#define _FDI_TXB_CTL 0x61100 +#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL) #define FDI_TX_DISABLE (0<<31) #define FDI_TX_ENABLE (1<<31) #define FDI_LINK_TRAIN_PATTERN_1 (0<<28) @@ -3058,9 +3099,9 @@ #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_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL) +#define _FDI_RXA_CTL 0xf000c +#define _FDI_RXB_CTL 0xf100c +#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) #define FDI_RX_ENABLE (1<<31) /* train, dp width same as FDI_TX */ #define FDI_DP_PORT_WIDTH_X8 (7<<19) @@ -3085,15 +3126,15 @@ #define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) #define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) -#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 -#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC) -#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1) -#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2) +#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 +#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) +#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1) +#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) /* FDI_RX interrupt register format */ #define FDI_RX_INTER_LANE_ALIGN (1<<10) @@ -3108,12 +3149,12 @@ #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_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR) -#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR) +#define _FDI_RXA_IIR 0xf0014 +#define _FDI_RXA_IMR 0xf0018 +#define _FDI_RXB_IIR 0xf1014 +#define _FDI_RXB_IMR 0xf1018 +#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR) +#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR) #define FDI_PLL_CTL_1 0xfe000 #define FDI_PLL_CTL_2 0xfe004 @@ -3143,11 +3184,15 @@ #define ADPA_CRT_HOTPLUG_VOLREF_475MV (1<<17) #define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) +#define ADPA_PIPE_ENABLED(V, P) \ + (((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE)) + /* or SDVOB */ #define HDMIB 0xe1140 #define PORT_ENABLE (1 << 31) #define TRANSCODER_A (0) #define TRANSCODER_B (1 << 30) +#define TRANSCODER_MASK (1 << 30) #define COLOR_FORMAT_8bpc (0) #define COLOR_FORMAT_12bpc (3 << 26) #define SDVOB_HOTPLUG_ENABLE (1 << 23) @@ -3163,6 +3208,9 @@ #define HSYNC_ACTIVE_HIGH (1 << 3) #define PORT_DETECTED (1 << 2) +#define HDMI_PIPE_ENABLED(V, P) \ + (((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE)) + /* PCH SDVOB multiplex with HDMIB */ #define PCH_SDVOB HDMIB @@ -3238,6 +3286,7 @@ #define TRANS_DP_PORT_SEL_B (0<<29) #define TRANS_DP_PORT_SEL_C (1<<29) #define TRANS_DP_PORT_SEL_D (2<<29) +#define TRANS_DP_PORT_SEL_NONE (3<<29) #define TRANS_DP_PORT_SEL_MASK (3<<29) #define TRANS_DP_AUDIO_ONLY (1<<26) #define TRANS_DP_ENH_FRAMING (1<<18) @@ -3269,6 +3318,8 @@ #define FORCEWAKE 0xA18C #define FORCEWAKE_ACK 0x130090 +#define GT_FIFO_FREE_ENTRIES 0x120008 + #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) @@ -3286,15 +3337,28 @@ #define GEN6_RP_DOWN_TIMEOUT 0xA010 #define GEN6_RP_INTERRUPT_LIMITS 0xA014 #define GEN6_RPSTAT1 0xA01C +#define GEN6_CAGF_SHIFT 8 +#define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) #define GEN6_RP_CONTROL 0xA024 #define GEN6_RP_MEDIA_TURBO (1<<11) #define GEN6_RP_USE_NORMAL_FREQ (1<<9) #define GEN6_RP_MEDIA_IS_GFX (1<<8) #define GEN6_RP_ENABLE (1<<7) -#define GEN6_RP_UP_BUSY_MAX (0x2<<3) -#define GEN6_RP_DOWN_BUSY_MIN (0x2<<0) +#define GEN6_RP_UP_IDLE_MIN (0x1<<3) +#define GEN6_RP_UP_BUSY_AVG (0x2<<3) +#define GEN6_RP_UP_BUSY_CONT (0x4<<3) +#define GEN6_RP_DOWN_IDLE_CONT (0x1<<0) #define GEN6_RP_UP_THRESHOLD 0xA02C #define GEN6_RP_DOWN_THRESHOLD 0xA030 +#define GEN6_RP_CUR_UP_EI 0xA050 +#define GEN6_CURICONT_MASK 0xffffff +#define GEN6_RP_CUR_UP 0xA054 +#define GEN6_CURBSYTAVG_MASK 0xffffff +#define GEN6_RP_PREV_UP 0xA058 +#define GEN6_RP_CUR_DOWN_EI 0xA05C +#define GEN6_CURIAVG_MASK 0xffffff +#define GEN6_RP_CUR_DOWN 0xA060 +#define GEN6_RP_PREV_DOWN 0xA064 #define GEN6_RP_UP_EI 0xA068 #define GEN6_RP_DOWN_EI 0xA06C #define GEN6_RP_IDLE_HYSTERSIS 0xA070 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 0521ecf2601..7e992a8e909 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -34,11 +34,10 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll_reg; - if (HAS_PCH_SPLIT(dev)) { - dpll_reg = (pipe == PIPE_A) ? PCH_DPLL_A: PCH_DPLL_B; - } else { - dpll_reg = (pipe == PIPE_A) ? DPLL_A: DPLL_B; - } + if (HAS_PCH_SPLIT(dev)) + dpll_reg = (pipe == PIPE_A) ? _PCH_DPLL_A : _PCH_DPLL_B; + else + dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE); } @@ -46,7 +45,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) static void i915_save_palette(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); u32 *array; int i; @@ -54,7 +53,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) return; if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; + reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; if (pipe == PIPE_A) array = dev_priv->save_palette_a; @@ -68,7 +67,7 @@ static void i915_save_palette(struct drm_device *dev, enum pipe pipe) static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? PALETTE_A : PALETTE_B); + unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); u32 *array; int i; @@ -76,7 +75,7 @@ static void i915_restore_palette(struct drm_device *dev, enum pipe pipe) return; if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? LGC_PALETTE_A : LGC_PALETTE_B; + reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; if (pipe == PIPE_A) array = dev_priv->save_palette_a; @@ -241,12 +240,12 @@ static void i915_save_modeset_reg(struct drm_device *dev) return; /* 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); + 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_GEN2(dev)) dev_priv->saveCURSIZE = I915_READ(CURSIZE); @@ -256,118 +255,118 @@ static void i915_save_modeset_reg(struct drm_device *dev) } /* Pipe & plane A info */ - dev_priv->savePIPEACONF = I915_READ(PIPEACONF); - dev_priv->savePIPEASRC = I915_READ(PIPEASRC); + dev_priv->savePIPEACONF = I915_READ(_PIPEACONF); + dev_priv->savePIPEASRC = I915_READ(_PIPEASRC); if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveFPA0 = I915_READ(PCH_FPA0); - dev_priv->saveFPA1 = I915_READ(PCH_FPA1); - dev_priv->saveDPLL_A = I915_READ(PCH_DPLL_A); + dev_priv->saveFPA0 = I915_READ(_PCH_FPA0); + dev_priv->saveFPA1 = I915_READ(_PCH_FPA1); + dev_priv->saveDPLL_A = I915_READ(_PCH_DPLL_A); } else { - dev_priv->saveFPA0 = I915_READ(FPA0); - dev_priv->saveFPA1 = I915_READ(FPA1); - dev_priv->saveDPLL_A = I915_READ(DPLL_A); + dev_priv->saveFPA0 = I915_READ(_FPA0); + dev_priv->saveFPA1 = I915_READ(_FPA1); + dev_priv->saveDPLL_A = I915_READ(_DPLL_A); } if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD); - dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A); - dev_priv->saveHBLANK_A = I915_READ(HBLANK_A); - dev_priv->saveHSYNC_A = I915_READ(HSYNC_A); - dev_priv->saveVTOTAL_A = I915_READ(VTOTAL_A); - dev_priv->saveVBLANK_A = I915_READ(VBLANK_A); - dev_priv->saveVSYNC_A = I915_READ(VSYNC_A); + dev_priv->saveDPLL_A_MD = I915_READ(_DPLL_A_MD); + dev_priv->saveHTOTAL_A = I915_READ(_HTOTAL_A); + dev_priv->saveHBLANK_A = I915_READ(_HBLANK_A); + dev_priv->saveHSYNC_A = I915_READ(_HSYNC_A); + dev_priv->saveVTOTAL_A = I915_READ(_VTOTAL_A); + dev_priv->saveVBLANK_A = I915_READ(_VBLANK_A); + dev_priv->saveVSYNC_A = I915_READ(_VSYNC_A); if (!HAS_PCH_SPLIT(dev)) - dev_priv->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + dev_priv->saveBCLRPAT_A = I915_READ(_BCLRPAT_A); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePIPEA_DATA_M1 = I915_READ(PIPEA_DATA_M1); - dev_priv->savePIPEA_DATA_N1 = I915_READ(PIPEA_DATA_N1); - dev_priv->savePIPEA_LINK_M1 = I915_READ(PIPEA_LINK_M1); - dev_priv->savePIPEA_LINK_N1 = I915_READ(PIPEA_LINK_N1); - - dev_priv->saveFDI_TXA_CTL = I915_READ(FDI_TXA_CTL); - dev_priv->saveFDI_RXA_CTL = I915_READ(FDI_RXA_CTL); - - dev_priv->savePFA_CTL_1 = I915_READ(PFA_CTL_1); - dev_priv->savePFA_WIN_SZ = I915_READ(PFA_WIN_SZ); - dev_priv->savePFA_WIN_POS = I915_READ(PFA_WIN_POS); - - dev_priv->saveTRANSACONF = I915_READ(TRANSACONF); - dev_priv->saveTRANS_HTOTAL_A = I915_READ(TRANS_HTOTAL_A); - dev_priv->saveTRANS_HBLANK_A = I915_READ(TRANS_HBLANK_A); - dev_priv->saveTRANS_HSYNC_A = I915_READ(TRANS_HSYNC_A); - dev_priv->saveTRANS_VTOTAL_A = I915_READ(TRANS_VTOTAL_A); - dev_priv->saveTRANS_VBLANK_A = I915_READ(TRANS_VBLANK_A); - dev_priv->saveTRANS_VSYNC_A = I915_READ(TRANS_VSYNC_A); - } - - dev_priv->saveDSPACNTR = I915_READ(DSPACNTR); - dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); - dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); - dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); - dev_priv->saveDSPAADDR = I915_READ(DSPAADDR); + dev_priv->savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); + dev_priv->savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); + dev_priv->savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); + dev_priv->savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); + + dev_priv->saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); + dev_priv->saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); + + dev_priv->savePFA_CTL_1 = I915_READ(_PFA_CTL_1); + dev_priv->savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); + dev_priv->savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); + + dev_priv->saveTRANSACONF = I915_READ(_TRANSACONF); + dev_priv->saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); + dev_priv->saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); + dev_priv->saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); + dev_priv->saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); + dev_priv->saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); + dev_priv->saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); + } + + dev_priv->saveDSPACNTR = I915_READ(_DSPACNTR); + dev_priv->saveDSPASTRIDE = I915_READ(_DSPASTRIDE); + dev_priv->saveDSPASIZE = I915_READ(_DSPASIZE); + dev_priv->saveDSPAPOS = I915_READ(_DSPAPOS); + dev_priv->saveDSPAADDR = I915_READ(_DSPAADDR); if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->saveDSPASURF = I915_READ(DSPASURF); - dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); + dev_priv->saveDSPASURF = I915_READ(_DSPASURF); + dev_priv->saveDSPATILEOFF = I915_READ(_DSPATILEOFF); } i915_save_palette(dev, PIPE_A); - dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT); + dev_priv->savePIPEASTAT = I915_READ(_PIPEASTAT); /* Pipe & plane B info */ - dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); - dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); + dev_priv->savePIPEBCONF = I915_READ(_PIPEBCONF); + dev_priv->savePIPEBSRC = I915_READ(_PIPEBSRC); if (HAS_PCH_SPLIT(dev)) { - dev_priv->saveFPB0 = I915_READ(PCH_FPB0); - dev_priv->saveFPB1 = I915_READ(PCH_FPB1); - dev_priv->saveDPLL_B = I915_READ(PCH_DPLL_B); + dev_priv->saveFPB0 = I915_READ(_PCH_FPB0); + dev_priv->saveFPB1 = I915_READ(_PCH_FPB1); + dev_priv->saveDPLL_B = I915_READ(_PCH_DPLL_B); } else { - dev_priv->saveFPB0 = I915_READ(FPB0); - dev_priv->saveFPB1 = I915_READ(FPB1); - dev_priv->saveDPLL_B = I915_READ(DPLL_B); + dev_priv->saveFPB0 = I915_READ(_FPB0); + dev_priv->saveFPB1 = I915_READ(_FPB1); + dev_priv->saveDPLL_B = I915_READ(_DPLL_B); } if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD); - dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B); - dev_priv->saveHBLANK_B = I915_READ(HBLANK_B); - dev_priv->saveHSYNC_B = I915_READ(HSYNC_B); - dev_priv->saveVTOTAL_B = I915_READ(VTOTAL_B); - dev_priv->saveVBLANK_B = I915_READ(VBLANK_B); - dev_priv->saveVSYNC_B = I915_READ(VSYNC_B); + dev_priv->saveDPLL_B_MD = I915_READ(_DPLL_B_MD); + dev_priv->saveHTOTAL_B = I915_READ(_HTOTAL_B); + dev_priv->saveHBLANK_B = I915_READ(_HBLANK_B); + dev_priv->saveHSYNC_B = I915_READ(_HSYNC_B); + dev_priv->saveVTOTAL_B = I915_READ(_VTOTAL_B); + dev_priv->saveVBLANK_B = I915_READ(_VBLANK_B); + dev_priv->saveVSYNC_B = I915_READ(_VSYNC_B); if (!HAS_PCH_SPLIT(dev)) - dev_priv->saveBCLRPAT_B = I915_READ(BCLRPAT_B); + dev_priv->saveBCLRPAT_B = I915_READ(_BCLRPAT_B); if (HAS_PCH_SPLIT(dev)) { - dev_priv->savePIPEB_DATA_M1 = I915_READ(PIPEB_DATA_M1); - dev_priv->savePIPEB_DATA_N1 = I915_READ(PIPEB_DATA_N1); - dev_priv->savePIPEB_LINK_M1 = I915_READ(PIPEB_LINK_M1); - dev_priv->savePIPEB_LINK_N1 = I915_READ(PIPEB_LINK_N1); - - dev_priv->saveFDI_TXB_CTL = I915_READ(FDI_TXB_CTL); - dev_priv->saveFDI_RXB_CTL = I915_READ(FDI_RXB_CTL); - - dev_priv->savePFB_CTL_1 = I915_READ(PFB_CTL_1); - dev_priv->savePFB_WIN_SZ = I915_READ(PFB_WIN_SZ); - dev_priv->savePFB_WIN_POS = I915_READ(PFB_WIN_POS); - - dev_priv->saveTRANSBCONF = I915_READ(TRANSBCONF); - dev_priv->saveTRANS_HTOTAL_B = I915_READ(TRANS_HTOTAL_B); - dev_priv->saveTRANS_HBLANK_B = I915_READ(TRANS_HBLANK_B); - dev_priv->saveTRANS_HSYNC_B = I915_READ(TRANS_HSYNC_B); - dev_priv->saveTRANS_VTOTAL_B = I915_READ(TRANS_VTOTAL_B); - dev_priv->saveTRANS_VBLANK_B = I915_READ(TRANS_VBLANK_B); - dev_priv->saveTRANS_VSYNC_B = I915_READ(TRANS_VSYNC_B); - } - - dev_priv->saveDSPBCNTR = I915_READ(DSPBCNTR); - dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); - dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); - dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); - dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); + dev_priv->savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); + dev_priv->savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); + dev_priv->savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); + dev_priv->savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); + + dev_priv->saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); + dev_priv->saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); + + dev_priv->savePFB_CTL_1 = I915_READ(_PFB_CTL_1); + dev_priv->savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); + dev_priv->savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); + + dev_priv->saveTRANSBCONF = I915_READ(_TRANSBCONF); + dev_priv->saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); + dev_priv->saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); + dev_priv->saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); + dev_priv->saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); + dev_priv->saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); + dev_priv->saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); + } + + dev_priv->saveDSPBCNTR = I915_READ(_DSPBCNTR); + dev_priv->saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); + dev_priv->saveDSPBSIZE = I915_READ(_DSPBSIZE); + dev_priv->saveDSPBPOS = I915_READ(_DSPBPOS); + dev_priv->saveDSPBADDR = I915_READ(_DSPBADDR); if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); - dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); + dev_priv->saveDSPBSURF = I915_READ(_DSPBSURF); + dev_priv->saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); - dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); + dev_priv->savePIPEBSTAT = I915_READ(_PIPEBSTAT); /* Fences */ switch (INTEL_INFO(dev)->gen) { @@ -426,19 +425,19 @@ static void i915_restore_modeset_reg(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { - dpll_a_reg = PCH_DPLL_A; - dpll_b_reg = PCH_DPLL_B; - fpa0_reg = PCH_FPA0; - fpb0_reg = PCH_FPB0; - fpa1_reg = PCH_FPA1; - fpb1_reg = PCH_FPB1; + dpll_a_reg = _PCH_DPLL_A; + dpll_b_reg = _PCH_DPLL_B; + fpa0_reg = _PCH_FPA0; + fpb0_reg = _PCH_FPB0; + fpa1_reg = _PCH_FPA1; + fpb1_reg = _PCH_FPB1; } else { - dpll_a_reg = DPLL_A; - dpll_b_reg = DPLL_B; - fpa0_reg = FPA0; - fpb0_reg = FPB0; - fpa1_reg = FPA1; - fpb1_reg = FPB1; + dpll_a_reg = _DPLL_A; + dpll_b_reg = _DPLL_B; + fpa0_reg = _FPA0; + fpb0_reg = _FPB0; + fpa1_reg = _FPA1; + fpb1_reg = _FPB1; } if (HAS_PCH_SPLIT(dev)) { @@ -461,60 +460,60 @@ static void i915_restore_modeset_reg(struct drm_device *dev) POSTING_READ(dpll_a_reg); udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); - POSTING_READ(DPLL_A_MD); + I915_WRITE(_DPLL_A_MD, dev_priv->saveDPLL_A_MD); + POSTING_READ(_DPLL_A_MD); } udelay(150); /* Restore mode */ - I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A); - I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A); - I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A); - I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A); - I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A); - I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A); + I915_WRITE(_HTOTAL_A, dev_priv->saveHTOTAL_A); + I915_WRITE(_HBLANK_A, dev_priv->saveHBLANK_A); + I915_WRITE(_HSYNC_A, dev_priv->saveHSYNC_A); + I915_WRITE(_VTOTAL_A, dev_priv->saveVTOTAL_A); + I915_WRITE(_VBLANK_A, dev_priv->saveVBLANK_A); + I915_WRITE(_VSYNC_A, dev_priv->saveVSYNC_A); if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A); + I915_WRITE(_BCLRPAT_A, dev_priv->saveBCLRPAT_A); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); - I915_WRITE(PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); - I915_WRITE(PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); - I915_WRITE(PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1); + I915_WRITE(_PIPEA_DATA_M1, dev_priv->savePIPEA_DATA_M1); + I915_WRITE(_PIPEA_DATA_N1, dev_priv->savePIPEA_DATA_N1); + I915_WRITE(_PIPEA_LINK_M1, dev_priv->savePIPEA_LINK_M1); + I915_WRITE(_PIPEA_LINK_N1, dev_priv->savePIPEA_LINK_N1); - I915_WRITE(FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL); - I915_WRITE(FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL); + I915_WRITE(_FDI_RXA_CTL, dev_priv->saveFDI_RXA_CTL); + I915_WRITE(_FDI_TXA_CTL, dev_priv->saveFDI_TXA_CTL); - I915_WRITE(PFA_CTL_1, dev_priv->savePFA_CTL_1); - I915_WRITE(PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ); - I915_WRITE(PFA_WIN_POS, dev_priv->savePFA_WIN_POS); + I915_WRITE(_PFA_CTL_1, dev_priv->savePFA_CTL_1); + I915_WRITE(_PFA_WIN_SZ, dev_priv->savePFA_WIN_SZ); + I915_WRITE(_PFA_WIN_POS, dev_priv->savePFA_WIN_POS); - I915_WRITE(TRANSACONF, dev_priv->saveTRANSACONF); - I915_WRITE(TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A); - I915_WRITE(TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A); - I915_WRITE(TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A); - I915_WRITE(TRANS_VTOTAL_A, dev_priv->saveTRANS_VTOTAL_A); - I915_WRITE(TRANS_VBLANK_A, dev_priv->saveTRANS_VBLANK_A); - I915_WRITE(TRANS_VSYNC_A, dev_priv->saveTRANS_VSYNC_A); + I915_WRITE(_TRANSACONF, dev_priv->saveTRANSACONF); + I915_WRITE(_TRANS_HTOTAL_A, dev_priv->saveTRANS_HTOTAL_A); + I915_WRITE(_TRANS_HBLANK_A, dev_priv->saveTRANS_HBLANK_A); + I915_WRITE(_TRANS_HSYNC_A, dev_priv->saveTRANS_HSYNC_A); + I915_WRITE(_TRANS_VTOTAL_A, dev_priv->saveTRANS_VTOTAL_A); + I915_WRITE(_TRANS_VBLANK_A, dev_priv->saveTRANS_VBLANK_A); + I915_WRITE(_TRANS_VSYNC_A, dev_priv->saveTRANS_VSYNC_A); } /* Restore plane info */ - I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); - I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); - I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); - I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + I915_WRITE(_DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(_DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(_PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(_DSPAADDR, dev_priv->saveDSPAADDR); + I915_WRITE(_DSPASTRIDE, dev_priv->saveDSPASTRIDE); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); - I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); + I915_WRITE(_DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(_DSPATILEOFF, dev_priv->saveDSPATILEOFF); } - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + I915_WRITE(_PIPEACONF, dev_priv->savePIPEACONF); i915_restore_palette(dev, PIPE_A); /* Enable the plane */ - I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); - I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); + I915_WRITE(_DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR)); /* Pipe & plane B info */ if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { @@ -530,68 +529,68 @@ static void i915_restore_modeset_reg(struct drm_device *dev) POSTING_READ(dpll_b_reg); udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); - POSTING_READ(DPLL_B_MD); + I915_WRITE(_DPLL_B_MD, dev_priv->saveDPLL_B_MD); + POSTING_READ(_DPLL_B_MD); } udelay(150); /* Restore mode */ - I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B); - I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B); - I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B); - I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B); - I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B); - I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B); + I915_WRITE(_HTOTAL_B, dev_priv->saveHTOTAL_B); + I915_WRITE(_HBLANK_B, dev_priv->saveHBLANK_B); + I915_WRITE(_HSYNC_B, dev_priv->saveHSYNC_B); + I915_WRITE(_VTOTAL_B, dev_priv->saveVTOTAL_B); + I915_WRITE(_VBLANK_B, dev_priv->saveVBLANK_B); + I915_WRITE(_VSYNC_B, dev_priv->saveVSYNC_B); if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B); + I915_WRITE(_BCLRPAT_B, dev_priv->saveBCLRPAT_B); if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); - I915_WRITE(PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); - I915_WRITE(PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); - I915_WRITE(PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1); + I915_WRITE(_PIPEB_DATA_M1, dev_priv->savePIPEB_DATA_M1); + I915_WRITE(_PIPEB_DATA_N1, dev_priv->savePIPEB_DATA_N1); + I915_WRITE(_PIPEB_LINK_M1, dev_priv->savePIPEB_LINK_M1); + I915_WRITE(_PIPEB_LINK_N1, dev_priv->savePIPEB_LINK_N1); - I915_WRITE(FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL); - I915_WRITE(FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL); + I915_WRITE(_FDI_RXB_CTL, dev_priv->saveFDI_RXB_CTL); + I915_WRITE(_FDI_TXB_CTL, dev_priv->saveFDI_TXB_CTL); - I915_WRITE(PFB_CTL_1, dev_priv->savePFB_CTL_1); - I915_WRITE(PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ); - I915_WRITE(PFB_WIN_POS, dev_priv->savePFB_WIN_POS); + I915_WRITE(_PFB_CTL_1, dev_priv->savePFB_CTL_1); + I915_WRITE(_PFB_WIN_SZ, dev_priv->savePFB_WIN_SZ); + I915_WRITE(_PFB_WIN_POS, dev_priv->savePFB_WIN_POS); - I915_WRITE(TRANSBCONF, dev_priv->saveTRANSBCONF); - I915_WRITE(TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B); - I915_WRITE(TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B); - I915_WRITE(TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B); - I915_WRITE(TRANS_VTOTAL_B, dev_priv->saveTRANS_VTOTAL_B); - I915_WRITE(TRANS_VBLANK_B, dev_priv->saveTRANS_VBLANK_B); - I915_WRITE(TRANS_VSYNC_B, dev_priv->saveTRANS_VSYNC_B); + I915_WRITE(_TRANSBCONF, dev_priv->saveTRANSBCONF); + I915_WRITE(_TRANS_HTOTAL_B, dev_priv->saveTRANS_HTOTAL_B); + I915_WRITE(_TRANS_HBLANK_B, dev_priv->saveTRANS_HBLANK_B); + I915_WRITE(_TRANS_HSYNC_B, dev_priv->saveTRANS_HSYNC_B); + I915_WRITE(_TRANS_VTOTAL_B, dev_priv->saveTRANS_VTOTAL_B); + I915_WRITE(_TRANS_VBLANK_B, dev_priv->saveTRANS_VBLANK_B); + I915_WRITE(_TRANS_VSYNC_B, dev_priv->saveTRANS_VSYNC_B); } /* Restore plane info */ - I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); - I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); - I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); - I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + I915_WRITE(_DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(_DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(_PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(_DSPBADDR, dev_priv->saveDSPBADDR); + I915_WRITE(_DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); - I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + I915_WRITE(_DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(_DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); } - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + I915_WRITE(_PIPEBCONF, dev_priv->savePIPEBCONF); i915_restore_palette(dev, PIPE_B); /* Enable the plane */ - I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); - I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); + 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); + 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_GEN2(dev)) I915_WRITE(CURSIZE, dev_priv->saveCURSIZE); @@ -653,14 +652,14 @@ void i915_save_display(struct drm_device *dev) dev_priv->saveDP_B = I915_READ(DP_B); dev_priv->saveDP_C = I915_READ(DP_C); dev_priv->saveDP_D = I915_READ(DP_D); - dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(PIPEA_GMCH_DATA_M); - dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(PIPEB_GMCH_DATA_M); - dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(PIPEA_GMCH_DATA_N); - dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(PIPEB_GMCH_DATA_N); - dev_priv->savePIPEA_DP_LINK_M = I915_READ(PIPEA_DP_LINK_M); - dev_priv->savePIPEB_DP_LINK_M = I915_READ(PIPEB_DP_LINK_M); - dev_priv->savePIPEA_DP_LINK_N = I915_READ(PIPEA_DP_LINK_N); - dev_priv->savePIPEB_DP_LINK_N = I915_READ(PIPEB_DP_LINK_N); + dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); + dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); + dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); + dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); + dev_priv->savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); + dev_priv->savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); + dev_priv->savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); + dev_priv->savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); } /* FIXME: save TV & SDVO state */ @@ -699,14 +698,14 @@ void i915_restore_display(struct drm_device *dev) /* Display port ratios (must be done before clock is set) */ if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M); - I915_WRITE(PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M); - I915_WRITE(PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N); - I915_WRITE(PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N); - I915_WRITE(PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M); - I915_WRITE(PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M); - I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); - I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); + I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); } /* This is only meaningful in non-KMS mode */ @@ -797,9 +796,6 @@ int i915_save_state(struct drm_device *dev) pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); - /* Hardware status page */ - dev_priv->saveHWS = I915_READ(HWS_PGA); - i915_save_display(dev); /* Interrupt state */ @@ -808,8 +804,8 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveDEIMR = I915_READ(DEIMR); dev_priv->saveGTIER = I915_READ(GTIER); dev_priv->saveGTIMR = I915_READ(GTIMR); - dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR); - dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR); + dev_priv->saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR); + dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = I915_READ(RSTDBYCTL); } else { @@ -846,9 +842,6 @@ int i915_restore_state(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); - /* Hardware status page */ - I915_WRITE(HWS_PGA, dev_priv->saveHWS); - i915_restore_display(dev); /* Interrupt state */ @@ -857,11 +850,11 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(DEIMR, dev_priv->saveDEIMR); I915_WRITE(GTIER, dev_priv->saveGTIER); I915_WRITE(GTIMR, dev_priv->saveGTIMR); - I915_WRITE(FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); - I915_WRITE(FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); + I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); + I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); } else { - I915_WRITE (IER, dev_priv->saveIER); - I915_WRITE (IMR, dev_priv->saveIMR); + I915_WRITE(IER, dev_priv->saveIER); + I915_WRITE(IMR, dev_priv->saveIMR); } /* Clock gating state */ diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 7f0fc3ed61a..d623fefbfac 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -7,6 +7,7 @@ #include <drm/drmP.h> #include "i915_drv.h" +#include "intel_ringbuffer.h" #undef TRACE_SYSTEM #define TRACE_SYSTEM i915 @@ -16,9 +17,7 @@ /* object tracking */ TRACE_EVENT(i915_gem_object_create, - TP_PROTO(struct drm_i915_gem_object *obj), - TP_ARGS(obj), TP_STRUCT__entry( @@ -35,33 +34,51 @@ TRACE_EVENT(i915_gem_object_create, ); TRACE_EVENT(i915_gem_object_bind, - - TP_PROTO(struct drm_i915_gem_object *obj, u32 gtt_offset, bool mappable), - - TP_ARGS(obj, gtt_offset, mappable), + TP_PROTO(struct drm_i915_gem_object *obj, bool mappable), + TP_ARGS(obj, mappable), TP_STRUCT__entry( __field(struct drm_i915_gem_object *, obj) - __field(u32, gtt_offset) + __field(u32, offset) + __field(u32, size) __field(bool, mappable) ), TP_fast_assign( __entry->obj = obj; - __entry->gtt_offset = gtt_offset; + __entry->offset = obj->gtt_space->start; + __entry->size = obj->gtt_space->size; __entry->mappable = mappable; ), - TP_printk("obj=%p, gtt_offset=%08x%s", - __entry->obj, __entry->gtt_offset, + TP_printk("obj=%p, offset=%08x size=%x%s", + __entry->obj, __entry->offset, __entry->size, __entry->mappable ? ", mappable" : "") ); -TRACE_EVENT(i915_gem_object_change_domain, +TRACE_EVENT(i915_gem_object_unbind, + TP_PROTO(struct drm_i915_gem_object *obj), + TP_ARGS(obj), + + TP_STRUCT__entry( + __field(struct drm_i915_gem_object *, obj) + __field(u32, offset) + __field(u32, size) + ), - TP_PROTO(struct drm_i915_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain), + TP_fast_assign( + __entry->obj = obj; + __entry->offset = obj->gtt_space->start; + __entry->size = obj->gtt_space->size; + ), - TP_ARGS(obj, old_read_domains, old_write_domain), + TP_printk("obj=%p, offset=%08x size=%x", + __entry->obj, __entry->offset, __entry->size) +); + +TRACE_EVENT(i915_gem_object_change_domain, + TP_PROTO(struct drm_i915_gem_object *obj, u32 old_read, u32 old_write), + TP_ARGS(obj, old_read, old_write), TP_STRUCT__entry( __field(struct drm_i915_gem_object *, obj) @@ -71,177 +88,264 @@ TRACE_EVENT(i915_gem_object_change_domain, TP_fast_assign( __entry->obj = obj; - __entry->read_domains = obj->base.read_domains | (old_read_domains << 16); - __entry->write_domain = obj->base.write_domain | (old_write_domain << 16); + __entry->read_domains = obj->base.read_domains | (old_read << 16); + __entry->write_domain = obj->base.write_domain | (old_write << 16); ), - TP_printk("obj=%p, read=%04x, write=%04x", + TP_printk("obj=%p, read=%02x=>%02x, write=%02x=>%02x", __entry->obj, - __entry->read_domains, __entry->write_domain) + __entry->read_domains >> 16, + __entry->read_domains & 0xffff, + __entry->write_domain >> 16, + __entry->write_domain & 0xffff) ); -DECLARE_EVENT_CLASS(i915_gem_object, +TRACE_EVENT(i915_gem_object_pwrite, + TP_PROTO(struct drm_i915_gem_object *obj, u32 offset, u32 len), + TP_ARGS(obj, offset, len), - TP_PROTO(struct drm_i915_gem_object *obj), + TP_STRUCT__entry( + __field(struct drm_i915_gem_object *, obj) + __field(u32, offset) + __field(u32, len) + ), - TP_ARGS(obj), + TP_fast_assign( + __entry->obj = obj; + __entry->offset = offset; + __entry->len = len; + ), + + TP_printk("obj=%p, offset=%u, len=%u", + __entry->obj, __entry->offset, __entry->len) +); + +TRACE_EVENT(i915_gem_object_pread, + TP_PROTO(struct drm_i915_gem_object *obj, u32 offset, u32 len), + TP_ARGS(obj, offset, len), TP_STRUCT__entry( __field(struct drm_i915_gem_object *, obj) + __field(u32, offset) + __field(u32, len) ), TP_fast_assign( __entry->obj = obj; + __entry->offset = offset; + __entry->len = len; ), - TP_printk("obj=%p", __entry->obj) + TP_printk("obj=%p, offset=%u, len=%u", + __entry->obj, __entry->offset, __entry->len) ); -DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush, +TRACE_EVENT(i915_gem_object_fault, + TP_PROTO(struct drm_i915_gem_object *obj, u32 index, bool gtt, bool write), + TP_ARGS(obj, index, gtt, write), + + TP_STRUCT__entry( + __field(struct drm_i915_gem_object *, obj) + __field(u32, index) + __field(bool, gtt) + __field(bool, write) + ), + + TP_fast_assign( + __entry->obj = obj; + __entry->index = index; + __entry->gtt = gtt; + __entry->write = write; + ), + TP_printk("obj=%p, %s index=%u %s", + __entry->obj, + __entry->gtt ? "GTT" : "CPU", + __entry->index, + __entry->write ? ", writable" : "") +); + +DECLARE_EVENT_CLASS(i915_gem_object, TP_PROTO(struct drm_i915_gem_object *obj), + TP_ARGS(obj), - TP_ARGS(obj) + TP_STRUCT__entry( + __field(struct drm_i915_gem_object *, obj) + ), + + TP_fast_assign( + __entry->obj = obj; + ), + + TP_printk("obj=%p", __entry->obj) ); -DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind, +DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush, + TP_PROTO(struct drm_i915_gem_object *obj), + TP_ARGS(obj) +); +DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy, TP_PROTO(struct drm_i915_gem_object *obj), - TP_ARGS(obj) ); -DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy, +TRACE_EVENT(i915_gem_evict, + TP_PROTO(struct drm_device *dev, u32 size, u32 align, bool mappable), + TP_ARGS(dev, size, align, mappable), - TP_PROTO(struct drm_i915_gem_object *obj), + TP_STRUCT__entry( + __field(u32, dev) + __field(u32, size) + __field(u32, align) + __field(bool, mappable) + ), - TP_ARGS(obj) + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->size = size; + __entry->align = align; + __entry->mappable = mappable; + ), + + TP_printk("dev=%d, size=%d, align=%d %s", + __entry->dev, __entry->size, __entry->align, + __entry->mappable ? ", mappable" : "") ); -/* batch tracing */ +TRACE_EVENT(i915_gem_evict_everything, + TP_PROTO(struct drm_device *dev, bool purgeable), + TP_ARGS(dev, purgeable), -TRACE_EVENT(i915_gem_request_submit, + TP_STRUCT__entry( + __field(u32, dev) + __field(bool, purgeable) + ), + + TP_fast_assign( + __entry->dev = dev->primary->index; + __entry->purgeable = purgeable; + ), - TP_PROTO(struct drm_device *dev, u32 seqno), + TP_printk("dev=%d%s", + __entry->dev, + __entry->purgeable ? ", purgeable only" : "") +); - TP_ARGS(dev, seqno), +TRACE_EVENT(i915_gem_ring_dispatch, + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno), TP_STRUCT__entry( __field(u32, dev) + __field(u32, ring) __field(u32, seqno) ), TP_fast_assign( - __entry->dev = dev->primary->index; + __entry->dev = ring->dev->primary->index; + __entry->ring = ring->id; __entry->seqno = seqno; - i915_trace_irq_get(dev, seqno); + i915_trace_irq_get(ring, seqno); ), - TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) + TP_printk("dev=%u, ring=%u, seqno=%u", + __entry->dev, __entry->ring, __entry->seqno) ); -TRACE_EVENT(i915_gem_request_flush, - - TP_PROTO(struct drm_device *dev, u32 seqno, - u32 flush_domains, u32 invalidate_domains), - - TP_ARGS(dev, seqno, flush_domains, invalidate_domains), +TRACE_EVENT(i915_gem_ring_flush, + TP_PROTO(struct intel_ring_buffer *ring, u32 invalidate, u32 flush), + TP_ARGS(ring, invalidate, flush), TP_STRUCT__entry( __field(u32, dev) - __field(u32, seqno) - __field(u32, flush_domains) - __field(u32, invalidate_domains) + __field(u32, ring) + __field(u32, invalidate) + __field(u32, flush) ), TP_fast_assign( - __entry->dev = dev->primary->index; - __entry->seqno = seqno; - __entry->flush_domains = flush_domains; - __entry->invalidate_domains = invalidate_domains; + __entry->dev = ring->dev->primary->index; + __entry->ring = ring->id; + __entry->invalidate = invalidate; + __entry->flush = flush; ), - TP_printk("dev=%u, seqno=%u, flush=%04x, invalidate=%04x", - __entry->dev, __entry->seqno, - __entry->flush_domains, __entry->invalidate_domains) + TP_printk("dev=%u, ring=%x, invalidate=%04x, flush=%04x", + __entry->dev, __entry->ring, + __entry->invalidate, __entry->flush) ); DECLARE_EVENT_CLASS(i915_gem_request, - - TP_PROTO(struct drm_device *dev, u32 seqno), - - TP_ARGS(dev, seqno), + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno), TP_STRUCT__entry( __field(u32, dev) + __field(u32, ring) __field(u32, seqno) ), TP_fast_assign( - __entry->dev = dev->primary->index; + __entry->dev = ring->dev->primary->index; + __entry->ring = ring->id; __entry->seqno = seqno; ), - TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) + TP_printk("dev=%u, ring=%u, seqno=%u", + __entry->dev, __entry->ring, __entry->seqno) ); -DEFINE_EVENT(i915_gem_request, i915_gem_request_complete, - - TP_PROTO(struct drm_device *dev, u32 seqno), +DEFINE_EVENT(i915_gem_request, i915_gem_request_add, + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno) +); - TP_ARGS(dev, seqno) +DEFINE_EVENT(i915_gem_request, i915_gem_request_complete, + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno) ); DEFINE_EVENT(i915_gem_request, i915_gem_request_retire, - - TP_PROTO(struct drm_device *dev, u32 seqno), - - TP_ARGS(dev, seqno) + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno) ); DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_begin, - - TP_PROTO(struct drm_device *dev, u32 seqno), - - TP_ARGS(dev, seqno) + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno) ); DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end, - - TP_PROTO(struct drm_device *dev, u32 seqno), - - TP_ARGS(dev, seqno) + TP_PROTO(struct intel_ring_buffer *ring, u32 seqno), + TP_ARGS(ring, seqno) ); DECLARE_EVENT_CLASS(i915_ring, - - TP_PROTO(struct drm_device *dev), - - TP_ARGS(dev), + TP_PROTO(struct intel_ring_buffer *ring), + TP_ARGS(ring), TP_STRUCT__entry( __field(u32, dev) + __field(u32, ring) ), TP_fast_assign( - __entry->dev = dev->primary->index; + __entry->dev = ring->dev->primary->index; + __entry->ring = ring->id; ), - TP_printk("dev=%u", __entry->dev) + TP_printk("dev=%u, ring=%u", __entry->dev, __entry->ring) ); DEFINE_EVENT(i915_ring, i915_ring_wait_begin, - - TP_PROTO(struct drm_device *dev), - - TP_ARGS(dev) + TP_PROTO(struct intel_ring_buffer *ring), + TP_ARGS(ring) ); DEFINE_EVENT(i915_ring, i915_ring_wait_end, - - TP_PROTO(struct drm_device *dev), - - TP_ARGS(dev) + TP_PROTO(struct intel_ring_buffer *ring), + TP_ARGS(ring) ); TRACE_EVENT(i915_flip_request, @@ -281,26 +385,29 @@ TRACE_EVENT(i915_flip_complete, ); TRACE_EVENT(i915_reg_rw, - TP_PROTO(int cmd, uint32_t reg, uint64_t val, int len), + TP_PROTO(bool write, u32 reg, u64 val, int len), - TP_ARGS(cmd, reg, val, len), + TP_ARGS(write, reg, val, len), TP_STRUCT__entry( - __field(int, cmd) - __field(uint32_t, reg) - __field(uint64_t, val) - __field(int, len) + __field(u64, val) + __field(u32, reg) + __field(u16, write) + __field(u16, len) ), TP_fast_assign( - __entry->cmd = cmd; + __entry->val = (u64)val; __entry->reg = reg; - __entry->val = (uint64_t)val; + __entry->write = write; __entry->len = len; ), - TP_printk("cmd=%c, reg=0x%x, val=0x%llx, len=%d", - __entry->cmd, __entry->reg, __entry->val, __entry->len) + TP_printk("%s reg=0x%x, len=%d, val=(0x%x, 0x%x)", + __entry->write ? "write" : "read", + __entry->reg, __entry->len, + (u32)(__entry->val & 0xffffffff), + (u32)(__entry->val >> 32)) ); #endif /* _I915_TRACE_H_ */ diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 0b44956c336..fb5b4d426ae 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -226,29 +226,49 @@ static void parse_sdvo_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) { - struct bdb_sdvo_lvds_options *sdvo_lvds_options; struct lvds_dvo_timing *dvo_timing; struct drm_display_mode *panel_fixed_mode; + int index; - sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); - if (!sdvo_lvds_options) - return; + index = i915_vbt_sdvo_panel_type; + if (index == -1) { + struct bdb_sdvo_lvds_options *sdvo_lvds_options; + + sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); + if (!sdvo_lvds_options) + return; + + index = sdvo_lvds_options->panel_type; + } dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); if (!dvo_timing) return; panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); - if (!panel_fixed_mode) return; - fill_detail_timing_data(panel_fixed_mode, - dvo_timing + sdvo_lvds_options->panel_type); + fill_detail_timing_data(panel_fixed_mode, dvo_timing + index); dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; - return; + DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n"); + drm_mode_debug_printmodeline(panel_fixed_mode); +} + +static int intel_bios_ssc_frequency(struct drm_device *dev, + bool alternate) +{ + switch (INTEL_INFO(dev)->gen) { + case 2: + return alternate ? 66 : 48; + case 3: + case 4: + return alternate ? 100 : 96; + default: + return alternate ? 100 : 120; + } } static void @@ -263,13 +283,8 @@ parse_general_features(struct drm_i915_private *dev_priv, dev_priv->int_tv_support = general->int_tv_support; dev_priv->int_crt_support = general->int_crt_support; dev_priv->lvds_use_ssc = general->enable_ssc; - - if (IS_I85X(dev)) - dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48; - else if (IS_GEN5(dev) || IS_GEN6(dev)) - dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120; - else - dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96; + dev_priv->lvds_ssc_freq = + intel_bios_ssc_frequency(dev, general->ssc_freq); } } @@ -553,6 +568,8 @@ parse_device_mapping(struct drm_i915_private *dev_priv, static void init_vbt_defaults(struct drm_i915_private *dev_priv) { + struct drm_device *dev = dev_priv->dev; + dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC; /* LFP panel data */ @@ -565,7 +582,11 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) /* general features */ dev_priv->int_tv_support = 1; dev_priv->int_crt_support = 1; - dev_priv->lvds_use_ssc = 0; + + /* Default to using SSC */ + dev_priv->lvds_use_ssc = 1; + dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); + DRM_DEBUG("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); /* eDP data */ dev_priv->edp.bpp = 18; diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8a77ff4a723..8342259f316 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -129,10 +129,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, 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; + dpll_md_reg = DPLL_MD(intel_crtc->pipe); if (HAS_PCH_SPLIT(dev)) adpa_reg = PCH_ADPA; @@ -160,17 +157,16 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, adpa |= PORT_TRANS_A_SEL_CPT; else adpa |= ADPA_PIPE_A_SELECT; - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(BCLRPAT_A, 0); } else { if (HAS_PCH_CPT(dev)) adpa |= PORT_TRANS_B_SEL_CPT; else adpa |= ADPA_PIPE_B_SELECT; - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(BCLRPAT_B, 0); } + if (!HAS_PCH_SPLIT(dev)) + I915_WRITE(BCLRPAT(intel_crtc->pipe), 0); + I915_WRITE(adpa_reg, adpa); } @@ -353,21 +349,12 @@ intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt) DRM_DEBUG_KMS("starting load-detect on CRT\n"); - if (pipe == 0) { - bclrpat_reg = BCLRPAT_A; - vtotal_reg = VTOTAL_A; - vblank_reg = VBLANK_A; - vsync_reg = VSYNC_A; - pipeconf_reg = PIPEACONF; - pipe_dsl_reg = PIPEADSL; - } else { - bclrpat_reg = BCLRPAT_B; - vtotal_reg = VTOTAL_B; - vblank_reg = VBLANK_B; - vsync_reg = VSYNC_B; - pipeconf_reg = PIPEBCONF; - pipe_dsl_reg = PIPEBDSL; - } + bclrpat_reg = BCLRPAT(pipe); + vtotal_reg = VTOTAL(pipe); + vblank_reg = VBLANK(pipe); + vsync_reg = VSYNC(pipe); + pipeconf_reg = PIPECONF(pipe); + pipe_dsl_reg = PIPEDSL(pipe); save_bclrpat = I915_READ(bclrpat_reg); save_vtotal = I915_READ(vtotal_reg); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e42aa58650..3106c0dc838 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -989,7 +989,7 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, void intel_wait_for_vblank(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - int pipestat_reg = (pipe == 0 ? PIPEASTAT : PIPEBSTAT); + int pipestat_reg = PIPESTAT(pipe); /* Clear existing vblank status. Note this will clear any other * sticky status fields as well. @@ -1058,6 +1058,612 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) } } +static const char *state_string(bool enabled) +{ + return enabled ? "on" : "off"; +} + +/* Only for pre-ILK configs */ +static void assert_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = DPLL(pipe); + val = I915_READ(reg); + cur_state = !!(val & DPLL_VCO_ENABLE); + WARN(cur_state != state, + "PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_pll_enabled(d, p) assert_pll(d, p, true) +#define assert_pll_disabled(d, p) assert_pll(d, p, false) + +/* For ILK+ */ +static void assert_pch_pll(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = PCH_DPLL(pipe); + val = I915_READ(reg); + cur_state = !!(val & DPLL_VCO_ENABLE); + WARN(cur_state != state, + "PCH PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_pch_pll_enabled(d, p) assert_pch_pll(d, p, true) +#define assert_pch_pll_disabled(d, p) assert_pch_pll(d, p, false) + +static void assert_fdi_tx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = FDI_TX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_TX_ENABLE); + WARN(cur_state != state, + "FDI TX state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_fdi_tx_enabled(d, p) assert_fdi_tx(d, p, true) +#define assert_fdi_tx_disabled(d, p) assert_fdi_tx(d, p, false) + +static void assert_fdi_rx(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + cur_state = !!(val & FDI_RX_ENABLE); + WARN(cur_state != state, + "FDI RX state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_fdi_rx_enabled(d, p) assert_fdi_rx(d, p, true) +#define assert_fdi_rx_disabled(d, p) assert_fdi_rx(d, p, false) + +static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* ILK FDI PLL is always enabled */ + if (dev_priv->info->gen == 5) + return; + + reg = FDI_TX_CTL(pipe); + val = I915_READ(reg); + WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n"); +} + +static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + reg = FDI_RX_CTL(pipe); + val = I915_READ(reg); + WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n"); +} + +static void assert_panel_unlocked(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int pp_reg, lvds_reg; + u32 val; + enum pipe panel_pipe = PIPE_A; + bool locked = locked; + + if (HAS_PCH_SPLIT(dev_priv->dev)) { + pp_reg = PCH_PP_CONTROL; + lvds_reg = PCH_LVDS; + } else { + pp_reg = PP_CONTROL; + lvds_reg = LVDS; + } + + val = I915_READ(pp_reg); + if (!(val & PANEL_POWER_ON) || + ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)) + locked = false; + + if (I915_READ(lvds_reg) & LVDS_PIPEB_SELECT) + panel_pipe = PIPE_B; + + WARN(panel_pipe == pipe && locked, + "panel assertion failure, pipe %c regs locked\n", + pipe_name(pipe)); +} + +static void assert_pipe(struct drm_i915_private *dev_priv, + enum pipe pipe, bool state) +{ + int reg; + u32 val; + bool cur_state; + + reg = PIPECONF(pipe); + val = I915_READ(reg); + cur_state = !!(val & PIPECONF_ENABLE); + WARN(cur_state != state, + "pipe %c assertion failure (expected %s, current %s)\n", + pipe_name(pipe), state_string(state), state_string(cur_state)); +} +#define assert_pipe_enabled(d, p) assert_pipe(d, p, true) +#define assert_pipe_disabled(d, p) assert_pipe(d, p, false) + +static void assert_plane_enabled(struct drm_i915_private *dev_priv, + enum plane plane) +{ + int reg; + u32 val; + + reg = DSPCNTR(plane); + val = I915_READ(reg); + WARN(!(val & DISPLAY_PLANE_ENABLE), + "plane %c assertion failure, should be active but is disabled\n", + plane_name(plane)); +} + +static void assert_planes_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg, i; + u32 val; + int cur_pipe; + + /* Planes are fixed to pipes on ILK+ */ + if (HAS_PCH_SPLIT(dev_priv->dev)) + return; + + /* Need to check both planes against the pipe */ + for (i = 0; i < 2; i++) { + reg = DSPCNTR(i); + val = I915_READ(reg); + cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >> + DISPPLANE_SEL_PIPE_SHIFT; + WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe, + "plane %c assertion failure, should be off on pipe %c but is still active\n", + plane_name(i), pipe_name(pipe)); + } +} + +static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) +{ + u32 val; + bool enabled; + + val = I915_READ(PCH_DREF_CONTROL); + enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK | + DREF_SUPERSPREAD_SOURCE_MASK)); + WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n"); +} + +static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + bool enabled; + + reg = TRANSCONF(pipe); + val = I915_READ(reg); + enabled = !!(val & TRANS_ENABLE); + WARN(enabled, + "transcoder assertion failed, should be off on pipe %c but is still active\n", + pipe_name(pipe)); +} + +static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg) +{ + u32 val = I915_READ(reg); + WARN(DP_PIPE_ENABLED(val, pipe), + "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", + reg, pipe_name(pipe)); +} + +static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg) +{ + u32 val = I915_READ(reg); + WARN(HDMI_PIPE_ENABLED(val, pipe), + "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", + reg, pipe_name(pipe)); +} + +static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D); + + reg = PCH_ADPA; + val = I915_READ(reg); + WARN(ADPA_PIPE_ENABLED(val, pipe), + "PCH VGA enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); + + reg = PCH_LVDS; + val = I915_READ(reg); + WARN(LVDS_PIPE_ENABLED(val, pipe), + "PCH LVDS enabled on transcoder %c, should be disabled\n", + pipe_name(pipe)); + + assert_pch_hdmi_disabled(dev_priv, pipe, HDMIB); + assert_pch_hdmi_disabled(dev_priv, pipe, HDMIC); + assert_pch_hdmi_disabled(dev_priv, pipe, HDMID); +} + +/** + * intel_enable_pll - enable a PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * + * Enable @pipe's PLL so we can start pumping pixels from a plane. Check to + * make sure the PLL reg is writable first though, since the panel write + * protect mechanism may be enabled. + * + * Note! This is for pre-ILK only. + */ +static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + int reg; + u32 val; + + /* No really, not for ILK+ */ + BUG_ON(dev_priv->info->gen >= 5); + + /* PLL is protected by panel, make sure we can write it */ + if (IS_MOBILE(dev_priv->dev) && !IS_I830(dev_priv->dev)) + assert_panel_unlocked(dev_priv, pipe); + + reg = DPLL(pipe); + val = I915_READ(reg); + val |= DPLL_VCO_ENABLE; + + /* We do this three times for luck */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(150); /* wait for warmup */ +} + +/** + * intel_disable_pll - disable a PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to disable + * + * Disable the PLL for @pipe, making sure the pipe is off first. + * + * Note! This is for pre-ILK only. + */ +static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) +{ + int reg; + u32 val; + + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; + + /* Make sure the pipe isn't still relying on us */ + assert_pipe_disabled(dev_priv, pipe); + + reg = DPLL(pipe); + val = I915_READ(reg); + val &= ~DPLL_VCO_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); +} + +/** + * intel_enable_pch_pll - enable PCH PLL + * @dev_priv: i915 private structure + * @pipe: pipe PLL to enable + * + * The PCH PLL needs to be enabled before the PCH transcoder, since it + * drives the transcoder clock. + */ +static void intel_enable_pch_pll(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* PCH refclock must be enabled first */ + assert_pch_refclk_enabled(dev_priv); + + reg = PCH_DPLL(pipe); + val = I915_READ(reg); + val |= DPLL_VCO_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(200); +} + +static void intel_disable_pch_pll(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* Make sure transcoder isn't still depending on us */ + assert_transcoder_disabled(dev_priv, pipe); + + reg = PCH_DPLL(pipe); + val = I915_READ(reg); + val &= ~DPLL_VCO_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + udelay(200); +} + +static void intel_enable_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* PCH only available on ILK+ */ + BUG_ON(dev_priv->info->gen < 5); + + /* Make sure PCH DPLL is enabled */ + assert_pch_pll_enabled(dev_priv, pipe); + + /* FDI must be feeding us bits for PCH ports */ + assert_fdi_tx_enabled(dev_priv, pipe); + assert_fdi_rx_enabled(dev_priv, pipe); + + reg = TRANSCONF(pipe); + val = I915_READ(reg); + /* + * make the BPC in transcoder be consistent with + * that in pipeconf reg. + */ + val &= ~PIPE_BPC_MASK; + val |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK; + I915_WRITE(reg, val | TRANS_ENABLE); + if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) + DRM_ERROR("failed to enable transcoder %d\n", pipe); +} + +static void intel_disable_transcoder(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* FDI relies on the transcoder */ + assert_fdi_tx_disabled(dev_priv, pipe); + assert_fdi_rx_disabled(dev_priv, pipe); + + /* Ports must be off as well */ + assert_pch_ports_disabled(dev_priv, pipe); + + reg = TRANSCONF(pipe); + val = I915_READ(reg); + val &= ~TRANS_ENABLE; + I915_WRITE(reg, val); + /* wait for PCH transcoder off, transcoder state */ + if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) + DRM_ERROR("failed to disable transcoder\n"); +} + +/** + * intel_enable_pipe - enable a pipe, asserting requirements + * @dev_priv: i915 private structure + * @pipe: pipe to enable + * @pch_port: on ILK+, is this pipe driving a PCH port or not + * + * Enable @pipe, making sure that various hardware specific requirements + * are met, if applicable, e.g. PLL enabled, LVDS pairs enabled, etc. + * + * @pipe should be %PIPE_A or %PIPE_B. + * + * Will wait until the pipe is actually running (i.e. first vblank) before + * returning. + */ +static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, + bool pch_port) +{ + int reg; + u32 val; + + /* + * A pipe without a PLL won't actually be able to drive bits from + * a plane. On ILK+ the pipe PLLs are integrated, so we don't + * need the check. + */ + if (!HAS_PCH_SPLIT(dev_priv->dev)) + assert_pll_enabled(dev_priv, pipe); + else { + if (pch_port) { + /* if driving the PCH, we need FDI enabled */ + assert_fdi_rx_pll_enabled(dev_priv, pipe); + assert_fdi_tx_pll_enabled(dev_priv, pipe); + } + /* FIXME: assert CPU port conditions for SNB+ */ + } + + reg = PIPECONF(pipe); + val = I915_READ(reg); + val |= PIPECONF_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +/** + * intel_disable_pipe - disable a pipe, asserting requirements + * @dev_priv: i915 private structure + * @pipe: pipe to disable + * + * Disable @pipe, making sure that various hardware specific requirements + * are met, if applicable, e.g. plane disabled, panel fitter off, etc. + * + * @pipe should be %PIPE_A or %PIPE_B. + * + * Will wait until the pipe has shut down before returning. + */ +static void intel_disable_pipe(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + int reg; + u32 val; + + /* + * Make sure planes won't keep trying to pump pixels to us, + * or we might hang the display. + */ + assert_planes_disabled(dev_priv, pipe); + + /* Don't disable pipe A or pipe A PLLs if needed */ + if (pipe == PIPE_A && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) + return; + + reg = PIPECONF(pipe); + val = I915_READ(reg); + val &= ~PIPECONF_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + intel_wait_for_pipe_off(dev_priv->dev, pipe); +} + +/** + * intel_enable_plane - enable a display plane on a given pipe + * @dev_priv: i915 private structure + * @plane: plane to enable + * @pipe: pipe being fed + * + * Enable @plane on @pipe, making sure that @pipe is running first. + */ +static void intel_enable_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) +{ + int reg; + u32 val; + + /* If the pipe isn't enabled, we can't pump pixels and may hang */ + assert_pipe_enabled(dev_priv, pipe); + + reg = DSPCNTR(plane); + val = I915_READ(reg); + val |= DISPLAY_PLANE_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +/* + * Plane regs are double buffered, going from enabled->disabled needs a + * trigger in order to latch. The display address reg provides this. + */ +static void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane) +{ + u32 reg = DSPADDR(plane); + I915_WRITE(reg, I915_READ(reg)); +} + +/** + * intel_disable_plane - disable a display plane + * @dev_priv: i915 private structure + * @plane: plane to disable + * @pipe: pipe consuming the data + * + * Disable @plane; should be an independent operation. + */ +static void intel_disable_plane(struct drm_i915_private *dev_priv, + enum plane plane, enum pipe pipe) +{ + int reg; + u32 val; + + reg = DSPCNTR(plane); + val = I915_READ(reg); + val &= ~DISPLAY_PLANE_ENABLE; + I915_WRITE(reg, val); + POSTING_READ(reg); + intel_flush_display_plane(dev_priv, plane); + intel_wait_for_vblank(dev_priv->dev, pipe); +} + +static void disable_pch_dp(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg) +{ + u32 val = I915_READ(reg); + if (DP_PIPE_ENABLED(val, pipe)) + I915_WRITE(reg, val & ~DP_PORT_EN); +} + +static void disable_pch_hdmi(struct drm_i915_private *dev_priv, + enum pipe pipe, int reg) +{ + u32 val = I915_READ(reg); + if (HDMI_PIPE_ENABLED(val, pipe)) + I915_WRITE(reg, val & ~PORT_ENABLE); +} + +/* Disable any ports connected to this transcoder */ +static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, + enum pipe pipe) +{ + u32 reg, val; + + val = I915_READ(PCH_PP_CONTROL); + I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); + + disable_pch_dp(dev_priv, pipe, PCH_DP_B); + disable_pch_dp(dev_priv, pipe, PCH_DP_C); + disable_pch_dp(dev_priv, pipe, PCH_DP_D); + + reg = PCH_ADPA; + val = I915_READ(reg); + if (ADPA_PIPE_ENABLED(val, pipe)) + I915_WRITE(reg, val & ~ADPA_DAC_ENABLE); + + reg = PCH_LVDS; + val = I915_READ(reg); + if (LVDS_PIPE_ENABLED(val, pipe)) { + I915_WRITE(reg, val & ~LVDS_PORT_EN); + POSTING_READ(reg); + udelay(100); + } + + disable_pch_hdmi(dev_priv, pipe, HDMIB); + disable_pch_hdmi(dev_priv, pipe, HDMIC); + disable_pch_hdmi(dev_priv, pipe, HDMID); +} + static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; @@ -1219,7 +1825,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) u32 blt_ecoskpd; /* Make sure blitter notifies FBC of writes */ - __gen6_force_wake_get(dev_priv); + __gen6_gt_force_wake_get(dev_priv); blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << GEN6_BLITTER_LOCK_SHIFT; @@ -1230,7 +1836,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) GEN6_BLITTER_LOCK_SHIFT); I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); POSTING_READ(GEN6_BLITTER_ECOSKPD); - __gen6_force_wake_put(dev_priv); + __gen6_gt_force_wake_put(dev_priv); } static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) @@ -1390,7 +1996,7 @@ static void intel_update_fbc(struct drm_device *dev) * - going to an unsupported config (interlace, pixel multiply, etc.) */ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { - if (tmp_crtc->enabled) { + if (tmp_crtc->enabled && tmp_crtc->fb) { if (crtc) { DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; @@ -1461,6 +2067,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined) { + struct drm_i915_private *dev_priv = dev->dev_private; u32 alignment; int ret; @@ -1485,9 +2092,10 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, BUG(); } + dev_priv->mm.interruptible = false; ret = i915_gem_object_pin(obj, alignment, true); if (ret) - return ret; + goto err_interruptible; ret = i915_gem_object_set_to_display_plane(obj, pipelined); if (ret) @@ -1499,15 +2107,18 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * a fence as the cost is not that onerous. */ if (obj->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence(obj, pipelined, false); + ret = i915_gem_object_get_fence(obj, pipelined); if (ret) goto err_unpin; } + dev_priv->mm.interruptible = true; return 0; err_unpin: i915_gem_object_unpin(obj); +err_interruptible: + dev_priv->mm.interruptible = true; return ret; } @@ -1630,19 +2241,19 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; wait_event(dev_priv->pending_flip_queue, + atomic_read(&dev_priv->mm.wedged) || atomic_read(&obj->pending_flip) == 0); /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the * current scanout is retired before unpinning the old * framebuffer. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. */ - ret = i915_gem_object_flush_gpu(obj, false); - if (ret) { - i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); - mutex_unlock(&dev->struct_mutex); - return ret; - } + ret = i915_gem_object_flush_gpu(obj); + (void) ret; } ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, @@ -1753,8 +2364,13 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) 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->plane; u32 reg, temp, tries; + /* FDI needs bits from pipe & plane first */ + assert_pipe_enabled(dev_priv, pipe); + assert_plane_enabled(dev_priv, plane); + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ reg = FDI_RX_IMR(pipe); @@ -1784,7 +2400,11 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) udelay(150); /* Ironlake workaround, enable clock pointer after FDI enable*/ - I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE); + if (HAS_PCH_IBX(dev)) { + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR | + FDI_RX_PHASE_SYNC_POINTER_EN); + } reg = FDI_RX_IIR(pipe); for (tries = 0; tries < 5; tries++) { @@ -1834,7 +2454,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) } -static const int const snb_b_fdi_train_param [] = { +static const int snb_b_fdi_train_param [] = { FDI_LINK_TRAIN_400MV_0DB_SNB_B, FDI_LINK_TRAIN_400MV_6DB_SNB_B, FDI_LINK_TRAIN_600MV_3_5DB_SNB_B, @@ -2003,12 +2623,60 @@ static void ironlake_fdi_enable(struct drm_crtc *crtc) } } -static void intel_flush_display_plane(struct drm_device *dev, - int plane) +static void ironlake_fdi_disable(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg = DSPADDR(plane); - I915_WRITE(reg, I915_READ(reg)); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + u32 reg, temp; + + /* disable CPU FDI tx and PCH FDI rx */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + I915_WRITE(reg, temp & ~FDI_TX_ENABLE); + POSTING_READ(reg); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~(0x7 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + I915_WRITE(reg, temp & ~FDI_RX_ENABLE); + + POSTING_READ(reg); + udelay(100); + + /* Ironlake workaround, disable clock pointer after downing FDI */ + if (HAS_PCH_IBX(dev)) { + I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR); + I915_WRITE(FDI_RX_CHICKEN(pipe), + I915_READ(FDI_RX_CHICKEN(pipe) & + ~FDI_RX_PHASE_SYNC_POINTER_EN)); + } + + /* still set train pattern 1 */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + I915_WRITE(reg, temp); + + reg = FDI_RX_CTL(pipe); + temp = I915_READ(reg); + if (HAS_PCH_CPT(dev)) { + temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; + temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + } else { + temp &= ~FDI_LINK_TRAIN_NONE; + temp |= FDI_LINK_TRAIN_PATTERN_1; + } + /* BPC in FDI rx is consistent with that in PIPECONF */ + temp &= ~(0x07 << 16); + temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + I915_WRITE(reg, temp); + + POSTING_READ(reg); + udelay(100); } /* @@ -2045,60 +2713,46 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) atomic_read(&obj->pending_flip) == 0); } -static void ironlake_crtc_enable(struct drm_crtc *crtc) +static bool intel_crtc_driving_pch(struct drm_crtc *crtc) { 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->plane; - u32 reg, temp; - - if (intel_crtc->active) - return; - - intel_crtc->active = true; - intel_update_watermarks(dev); - - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if ((temp & LVDS_PORT_EN) == 0) - I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); - } + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_encoder *encoder; - ironlake_fdi_enable(crtc); + /* + * If there's a non-PCH eDP on this crtc, it must be DP_A, and that + * must be driven by its own crtc; no sharing is possible. + */ + list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { + if (encoder->base.crtc != crtc) + continue; - /* Enable panel fitting for LVDS */ - if (dev_priv->pch_pf_size && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) { - /* Force use of hard-coded filter coefficients - * as some pre-programmed values are broken, - * e.g. x201. - */ - I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, - PF_ENABLE | PF_FILTER_MED_3x3); - I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS, - dev_priv->pch_pf_pos); - I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, - dev_priv->pch_pf_size); + switch (encoder->type) { + case INTEL_OUTPUT_EDP: + if (!intel_encoder_is_pch_edp(&encoder->base)) + return false; + continue; + } } - /* Enable CPU pipe */ - reg = PIPECONF(pipe); - temp = I915_READ(reg); - if ((temp & PIPECONF_ENABLE) == 0) { - I915_WRITE(reg, temp | PIPECONF_ENABLE); - POSTING_READ(reg); - intel_wait_for_vblank(dev, intel_crtc->pipe); - } + return true; +} - /* configure and enable CPU plane */ - reg = DSPCNTR(plane); - temp = I915_READ(reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev, plane); - } +/* + * Enable PCH resources required for PCH ports: + * - PCH PLLs + * - FDI training & RX/TX + * - update transcoder timings + * - DP transcoding bits + * - transcoder + */ +static void ironlake_pch_enable(struct drm_crtc *crtc) +{ + 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; + u32 reg, temp; /* For PCH output, training FDI link */ if (IS_GEN6(dev)) @@ -2106,14 +2760,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) else ironlake_fdi_link_train(crtc); - /* enable PCH DPLL */ - reg = PCH_DPLL(pipe); - temp = I915_READ(reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(reg, temp | DPLL_VCO_ENABLE); - POSTING_READ(reg); - udelay(200); - } + intel_enable_pch_pll(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { /* Be sure PCH DPLL SEL is set */ @@ -2125,7 +2772,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PCH_DPLL_SEL, temp); } - /* set transcoder timing */ + /* set transcoder timing, panel must allow it */ + assert_panel_unlocked(dev_priv, pipe); I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe))); I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe))); I915_WRITE(TRANS_HSYNC(pipe), I915_READ(HSYNC(pipe))); @@ -2172,18 +2820,55 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(reg, temp); } - /* enable PCH transcoder */ - reg = TRANSCONF(pipe); - temp = I915_READ(reg); - /* - * make the BPC in transcoder be consistent with - * that in pipeconf reg. - */ - temp &= ~PIPE_BPC_MASK; - temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK; - I915_WRITE(reg, temp | TRANS_ENABLE); - if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100)) - DRM_ERROR("failed to enable transcoder %d\n", pipe); + intel_enable_transcoder(dev_priv, pipe); +} + +static void ironlake_crtc_enable(struct drm_crtc *crtc) +{ + 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->plane; + u32 temp; + bool is_pch_port; + + if (intel_crtc->active) + return; + + intel_crtc->active = true; + intel_update_watermarks(dev); + + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + temp = I915_READ(PCH_LVDS); + if ((temp & LVDS_PORT_EN) == 0) + I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN); + } + + is_pch_port = intel_crtc_driving_pch(crtc); + + if (is_pch_port) + ironlake_fdi_enable(crtc); + else + ironlake_fdi_disable(crtc); + + /* Enable panel fitting for LVDS */ + if (dev_priv->pch_pf_size && + (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) { + /* Force use of hard-coded filter coefficients + * as some pre-programmed values are broken, + * e.g. x201. + */ + I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3); + I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos); + I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); + } + + intel_enable_pipe(dev_priv, pipe, is_pch_port); + intel_enable_plane(dev_priv, plane, pipe); + + if (is_pch_port) + ironlake_pch_enable(crtc); intel_crtc_load_lut(crtc); intel_update_fbc(dev); @@ -2206,116 +2891,58 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) drm_vblank_off(dev, pipe); intel_crtc_update_cursor(crtc, false); - /* Disable display plane */ - reg = DSPCNTR(plane); - temp = I915_READ(reg); - if (temp & DISPLAY_PLANE_ENABLE) { - I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev, plane); - } + intel_disable_plane(dev_priv, plane, pipe); if (dev_priv->cfb_plane == plane && dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - /* disable cpu pipe, disable after all planes disabled */ - reg = PIPECONF(pipe); - temp = I915_READ(reg); - if (temp & PIPECONF_ENABLE) { - I915_WRITE(reg, temp & ~PIPECONF_ENABLE); - POSTING_READ(reg); - /* wait for cpu pipe off, pipe state */ - intel_wait_for_pipe_off(dev, intel_crtc->pipe); - } + intel_disable_pipe(dev_priv, pipe); /* Disable PF */ - I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0); - I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0); - - /* disable CPU FDI tx and PCH FDI rx */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~FDI_TX_ENABLE); - POSTING_READ(reg); - - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - temp &= ~(0x7 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; - I915_WRITE(reg, temp & ~FDI_RX_ENABLE); - - POSTING_READ(reg); - udelay(100); - - /* Ironlake workaround, disable clock pointer after downing FDI */ - if (HAS_PCH_IBX(dev)) - I915_WRITE(FDI_RX_CHICKEN(pipe), - I915_READ(FDI_RX_CHICKEN(pipe) & - ~FDI_RX_PHASE_SYNC_POINTER_ENABLE)); - - /* still set train pattern 1 */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_1; - I915_WRITE(reg, temp); - - reg = FDI_RX_CTL(pipe); - temp = I915_READ(reg); - if (HAS_PCH_CPT(dev)) { - temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; - temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; - } else { - temp &= ~FDI_LINK_TRAIN_NONE; - temp |= FDI_LINK_TRAIN_PATTERN_1; - } - /* BPC in FDI rx is consistent with that in PIPECONF */ - temp &= ~(0x07 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; - I915_WRITE(reg, temp); + I915_WRITE(PF_CTL(pipe), 0); + I915_WRITE(PF_WIN_SZ(pipe), 0); - POSTING_READ(reg); - udelay(100); + ironlake_fdi_disable(crtc); - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - temp = I915_READ(PCH_LVDS); - if (temp & LVDS_PORT_EN) { - I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN); - POSTING_READ(PCH_LVDS); - udelay(100); - } - } + /* This is a horrible layering violation; we should be doing this in + * the connector/encoder ->prepare instead, but we don't always have + * enough information there about the config to know whether it will + * actually be necessary or just cause undesired flicker. + */ + intel_disable_pch_ports(dev_priv, pipe); - /* disable PCH transcoder */ - reg = TRANSCONF(plane); - temp = I915_READ(reg); - if (temp & TRANS_ENABLE) { - I915_WRITE(reg, temp & ~TRANS_ENABLE); - /* wait for PCH transcoder off, transcoder state */ - if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) - DRM_ERROR("failed to disable transcoder\n"); - } + intel_disable_transcoder(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { /* disable TRANS_DP_CTL */ reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK); + temp |= TRANS_DP_PORT_SEL_NONE; I915_WRITE(reg, temp); /* disable DPLL_SEL */ temp = I915_READ(PCH_DPLL_SEL); - if (pipe == 0) - temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL); - else + switch (pipe) { + case 0: + temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL); + break; + case 1: temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL); + break; + case 2: + /* FIXME: manage transcoder PLLs? */ + temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL); + break; + default: + BUG(); /* wtf */ + } I915_WRITE(PCH_DPLL_SEL, temp); } /* disable PCH DPLL */ - reg = PCH_DPLL(pipe); - temp = I915_READ(reg); - I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); + intel_disable_pch_pll(dev_priv, pipe); /* Switch from PCDclk to Rawclk */ reg = FDI_RX_CTL(pipe); @@ -2372,9 +2999,12 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) { if (!enable && intel_crtc->overlay) { struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; mutex_lock(&dev->struct_mutex); - (void) intel_overlay_switch_off(intel_crtc->overlay, false); + dev_priv->mm.interruptible = false; + (void) intel_overlay_switch_off(intel_crtc->overlay); + dev_priv->mm.interruptible = true; mutex_unlock(&dev->struct_mutex); } @@ -2390,7 +3020,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 reg, temp; if (intel_crtc->active) return; @@ -2398,42 +3027,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_update_watermarks(dev); - /* Enable the DPLL */ - reg = DPLL(pipe); - temp = I915_READ(reg); - if ((temp & DPLL_VCO_ENABLE) == 0) { - I915_WRITE(reg, temp); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(reg); - udelay(150); - - I915_WRITE(reg, temp | DPLL_VCO_ENABLE); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(reg); - udelay(150); - - I915_WRITE(reg, temp | DPLL_VCO_ENABLE); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(reg); - udelay(150); - } - - /* Enable the pipe */ - reg = PIPECONF(pipe); - temp = I915_READ(reg); - if ((temp & PIPECONF_ENABLE) == 0) - I915_WRITE(reg, temp | PIPECONF_ENABLE); - - /* Enable the plane */ - reg = DSPCNTR(plane); - temp = I915_READ(reg); - if ((temp & DISPLAY_PLANE_ENABLE) == 0) { - I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev, plane); - } + intel_enable_pll(dev_priv, pipe); + intel_enable_pipe(dev_priv, pipe, false); + intel_enable_plane(dev_priv, plane, pipe); intel_crtc_load_lut(crtc); intel_update_fbc(dev); @@ -2450,7 +3046,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; - u32 reg, temp; if (!intel_crtc->active) return; @@ -2465,45 +3060,10 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) dev_priv->display.disable_fbc) dev_priv->display.disable_fbc(dev); - /* Disable display plane */ - reg = DSPCNTR(plane); - temp = I915_READ(reg); - if (temp & DISPLAY_PLANE_ENABLE) { - I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE); - /* Flush the plane changes */ - intel_flush_display_plane(dev, plane); - - /* Wait for vblank for the disable to take effect */ - if (IS_GEN2(dev)) - intel_wait_for_vblank(dev, pipe); - } - - /* Don't disable pipe A or pipe A PLLs if needed */ - if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - goto done; - - /* Next, disable display pipes */ - reg = PIPECONF(pipe); - temp = I915_READ(reg); - if (temp & PIPECONF_ENABLE) { - I915_WRITE(reg, temp & ~PIPECONF_ENABLE); - - /* Wait for the pipe to turn off */ - POSTING_READ(reg); - intel_wait_for_pipe_off(dev, pipe); - } - - reg = DPLL(pipe); - temp = I915_READ(reg); - if (temp & DPLL_VCO_ENABLE) { - I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE); - - /* Wait for the clocks to turn off. */ - POSTING_READ(reg); - udelay(150); - } + intel_disable_plane(dev_priv, plane, pipe); + intel_disable_pipe(dev_priv, pipe); + intel_disable_pll(dev_priv, pipe); -done: intel_crtc->active = false; intel_update_fbc(dev); intel_update_watermarks(dev); @@ -2565,7 +3125,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; break; default: - DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); + DRM_ERROR("Can't update pipe %c in SAREA\n", pipe_name(pipe)); break; } } @@ -2762,77 +3322,77 @@ struct intel_watermark_params { }; /* Pineview has different values for various configs */ -static struct intel_watermark_params pineview_display_wm = { +static const struct intel_watermark_params pineview_display_wm = { PINEVIEW_DISPLAY_FIFO, PINEVIEW_MAX_WM, PINEVIEW_DFT_WM, PINEVIEW_GUARD_WM, PINEVIEW_FIFO_LINE_SIZE }; -static struct intel_watermark_params pineview_display_hplloff_wm = { +static const struct intel_watermark_params pineview_display_hplloff_wm = { PINEVIEW_DISPLAY_FIFO, PINEVIEW_MAX_WM, PINEVIEW_DFT_HPLLOFF_WM, PINEVIEW_GUARD_WM, PINEVIEW_FIFO_LINE_SIZE }; -static struct intel_watermark_params pineview_cursor_wm = { +static const struct intel_watermark_params pineview_cursor_wm = { PINEVIEW_CURSOR_FIFO, PINEVIEW_CURSOR_MAX_WM, PINEVIEW_CURSOR_DFT_WM, PINEVIEW_CURSOR_GUARD_WM, PINEVIEW_FIFO_LINE_SIZE, }; -static struct intel_watermark_params pineview_cursor_hplloff_wm = { +static const struct intel_watermark_params pineview_cursor_hplloff_wm = { PINEVIEW_CURSOR_FIFO, PINEVIEW_CURSOR_MAX_WM, PINEVIEW_CURSOR_DFT_WM, PINEVIEW_CURSOR_GUARD_WM, PINEVIEW_FIFO_LINE_SIZE }; -static struct intel_watermark_params g4x_wm_info = { +static const struct intel_watermark_params g4x_wm_info = { G4X_FIFO_SIZE, G4X_MAX_WM, G4X_MAX_WM, 2, G4X_FIFO_LINE_SIZE, }; -static struct intel_watermark_params g4x_cursor_wm_info = { +static const struct intel_watermark_params g4x_cursor_wm_info = { I965_CURSOR_FIFO, I965_CURSOR_MAX_WM, I965_CURSOR_DFT_WM, 2, G4X_FIFO_LINE_SIZE, }; -static struct intel_watermark_params i965_cursor_wm_info = { +static const struct intel_watermark_params i965_cursor_wm_info = { I965_CURSOR_FIFO, I965_CURSOR_MAX_WM, I965_CURSOR_DFT_WM, 2, I915_FIFO_LINE_SIZE, }; -static struct intel_watermark_params i945_wm_info = { +static const struct intel_watermark_params i945_wm_info = { I945_FIFO_SIZE, I915_MAX_WM, 1, 2, I915_FIFO_LINE_SIZE }; -static struct intel_watermark_params i915_wm_info = { +static const struct intel_watermark_params i915_wm_info = { I915_FIFO_SIZE, I915_MAX_WM, 1, 2, I915_FIFO_LINE_SIZE }; -static struct intel_watermark_params i855_wm_info = { +static const struct intel_watermark_params i855_wm_info = { I855GM_FIFO_SIZE, I915_MAX_WM, 1, 2, I830_FIFO_LINE_SIZE }; -static struct intel_watermark_params i830_wm_info = { +static const struct intel_watermark_params i830_wm_info = { I830_FIFO_SIZE, I915_MAX_WM, 1, @@ -2840,31 +3400,28 @@ static struct intel_watermark_params i830_wm_info = { I830_FIFO_LINE_SIZE }; -static struct intel_watermark_params ironlake_display_wm_info = { +static const struct intel_watermark_params ironlake_display_wm_info = { ILK_DISPLAY_FIFO, ILK_DISPLAY_MAXWM, ILK_DISPLAY_DFTWM, 2, ILK_FIFO_LINE_SIZE }; - -static struct intel_watermark_params ironlake_cursor_wm_info = { +static const struct intel_watermark_params ironlake_cursor_wm_info = { ILK_CURSOR_FIFO, ILK_CURSOR_MAXWM, ILK_CURSOR_DFTWM, 2, ILK_FIFO_LINE_SIZE }; - -static struct intel_watermark_params ironlake_display_srwm_info = { +static const struct intel_watermark_params ironlake_display_srwm_info = { ILK_DISPLAY_SR_FIFO, ILK_DISPLAY_MAX_SRWM, ILK_DISPLAY_DFT_SRWM, 2, ILK_FIFO_LINE_SIZE }; - -static struct intel_watermark_params ironlake_cursor_srwm_info = { +static const struct intel_watermark_params ironlake_cursor_srwm_info = { ILK_CURSOR_SR_FIFO, ILK_CURSOR_MAX_SRWM, ILK_CURSOR_DFT_SRWM, @@ -2872,31 +3429,28 @@ static struct intel_watermark_params ironlake_cursor_srwm_info = { ILK_FIFO_LINE_SIZE }; -static struct intel_watermark_params sandybridge_display_wm_info = { +static const struct intel_watermark_params sandybridge_display_wm_info = { SNB_DISPLAY_FIFO, SNB_DISPLAY_MAXWM, SNB_DISPLAY_DFTWM, 2, SNB_FIFO_LINE_SIZE }; - -static struct intel_watermark_params sandybridge_cursor_wm_info = { +static const struct intel_watermark_params sandybridge_cursor_wm_info = { SNB_CURSOR_FIFO, SNB_CURSOR_MAXWM, SNB_CURSOR_DFTWM, 2, SNB_FIFO_LINE_SIZE }; - -static struct intel_watermark_params sandybridge_display_srwm_info = { +static const struct intel_watermark_params sandybridge_display_srwm_info = { SNB_DISPLAY_SR_FIFO, SNB_DISPLAY_MAX_SRWM, SNB_DISPLAY_DFT_SRWM, 2, SNB_FIFO_LINE_SIZE }; - -static struct intel_watermark_params sandybridge_cursor_srwm_info = { +static const struct intel_watermark_params sandybridge_cursor_srwm_info = { SNB_CURSOR_SR_FIFO, SNB_CURSOR_MAX_SRWM, SNB_CURSOR_DFT_SRWM, @@ -2924,7 +3478,8 @@ static struct intel_watermark_params sandybridge_cursor_srwm_info = { * will occur, and a display engine hang could result. */ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, - struct intel_watermark_params *wm, + const struct intel_watermark_params *wm, + int fifo_size, int pixel_size, unsigned long latency_ns) { @@ -2942,7 +3497,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required); - wm_size = wm->fifo_size - (entries_required + wm->guard_size); + wm_size = fifo_size - (entries_required + wm->guard_size); DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size); @@ -3115,15 +3670,28 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane) return size; } -static void pineview_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int unused, - int pixel_size) +static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) +{ + struct drm_crtc *crtc, *enabled = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->enabled && crtc->fb) { + if (enabled) + return NULL; + enabled = crtc; + } + } + + return enabled; +} + +static void pineview_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; const struct cxsr_latency *latency; u32 reg; unsigned long wm; - int sr_clock; latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, dev_priv->fsb_freq, dev_priv->mem_freq); @@ -3133,11 +3701,14 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, return; } - if (!planea_clock || !planeb_clock) { - sr_clock = planea_clock ? planea_clock : planeb_clock; + crtc = single_enabled_crtc(dev); + if (crtc) { + int clock = crtc->mode.clock; + int pixel_size = crtc->fb->bits_per_pixel / 8; /* Display SR */ - wm = intel_calculate_wm(sr_clock, &pineview_display_wm, + wm = intel_calculate_wm(clock, &pineview_display_wm, + pineview_display_wm.fifo_size, pixel_size, latency->display_sr); reg = I915_READ(DSPFW1); reg &= ~DSPFW_SR_MASK; @@ -3146,7 +3717,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); /* cursor SR */ - wm = intel_calculate_wm(sr_clock, &pineview_cursor_wm, + wm = intel_calculate_wm(clock, &pineview_cursor_wm, + pineview_display_wm.fifo_size, pixel_size, latency->cursor_sr); reg = I915_READ(DSPFW3); reg &= ~DSPFW_CURSOR_SR_MASK; @@ -3154,7 +3726,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, I915_WRITE(DSPFW3, reg); /* Display HPLL off SR */ - wm = intel_calculate_wm(sr_clock, &pineview_display_hplloff_wm, + wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, pixel_size, latency->display_hpll_disable); reg = I915_READ(DSPFW3); reg &= ~DSPFW_HPLL_SR_MASK; @@ -3162,7 +3735,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, I915_WRITE(DSPFW3, reg); /* cursor HPLL off SR */ - wm = intel_calculate_wm(sr_clock, &pineview_cursor_hplloff_wm, + wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, pixel_size, latency->cursor_hpll_disable); reg = I915_READ(DSPFW3); reg &= ~DSPFW_HPLL_CURSOR_MASK; @@ -3180,125 +3754,229 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, } } -static void g4x_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size) +static bool g4x_compute_wm0(struct drm_device *dev, + int plane, + const struct intel_watermark_params *display, + int display_latency_ns, + const struct intel_watermark_params *cursor, + int cursor_latency_ns, + int *plane_wm, + int *cursor_wm) { - struct drm_i915_private *dev_priv = dev->dev_private; - int total_size, cacheline_size; - int planea_wm, planeb_wm, cursora_wm, cursorb_wm, cursor_sr; - struct intel_watermark_params planea_params, planeb_params; - unsigned long line_time_us; - int sr_clock, sr_entries = 0, entries_required; + struct drm_crtc *crtc; + int htotal, hdisplay, clock, pixel_size; + int line_time_us, line_count; + int entries, tlb_miss; - /* Create copies of the base settings for each pipe */ - planea_params = planeb_params = g4x_wm_info; + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) + return false; - /* Grab a couple of global values before we overwrite them */ - total_size = planea_params.fifo_size; - cacheline_size = planea_params.cacheline_size; + htotal = crtc->mode.htotal; + hdisplay = crtc->mode.hdisplay; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; - /* - * Note: we need to make sure we don't overflow for various clock & - * latency values. - * clocks go from a few thousand to several hundred thousand. - * latency is usually a few thousand - */ - entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) / - 1000; - entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); - planea_wm = entries_required + planea_params.guard_size; + /* Use the small buffer method to calculate plane watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *plane_wm = entries + display->guard_size; + if (*plane_wm > (int)display->max_wm) + *plane_wm = display->max_wm; - entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) / - 1000; - entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); - planeb_wm = entries_required + planeb_params.guard_size; + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = ((htotal * 1000) / clock); + line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; + entries = line_count * 64 * pixel_size; + tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + if (*cursor_wm > (int)cursor->max_wm) + *cursor_wm = (int)cursor->max_wm; - cursora_wm = cursorb_wm = 16; - cursor_sr = 32; + return true; +} - DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + */ +static bool g4x_check_srwm(struct drm_device *dev, + int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) +{ + DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n", + display_wm, cursor_wm); - /* Calc sr entries for one plane configs */ - if (sr_hdisplay && (!planea_clock || !planeb_clock)) { - /* self-refresh has much higher latency */ - static const int sr_latency_ns = 12000; + if (display_wm > display->max_wm) { + DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n", + display_wm, display->max_wm); + return false; + } - sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_htotal * 1000) / sr_clock); + if (cursor_wm > cursor->max_wm) { + DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n", + cursor_wm, cursor->max_wm); + return false; + } - /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; - sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); - - entries_required = (((sr_latency_ns / line_time_us) + - 1000) / 1000) * pixel_size * 64; - entries_required = DIV_ROUND_UP(entries_required, - g4x_cursor_wm_info.cacheline_size); - cursor_sr = entries_required + g4x_cursor_wm_info.guard_size; - - if (cursor_sr > g4x_cursor_wm_info.max_wm) - cursor_sr = g4x_cursor_wm_info.max_wm; - DRM_DEBUG_KMS("self-refresh watermark: display plane %d " - "cursor %d\n", sr_entries, cursor_sr); + if (!(display_wm || cursor_wm)) { + DRM_DEBUG_KMS("SR latency is 0, disabling\n"); + return false; + } - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - } else { - /* Turn off self refresh if both pipes are enabled */ - I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) - & ~FW_BLC_SELF_EN); + return true; +} + +static bool g4x_compute_srwm(struct drm_device *dev, + int plane, + int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *display_wm, int *cursor_wm) +{ + struct drm_crtc *crtc; + int hdisplay, htotal, pixel_size, clock; + unsigned long line_time_us; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *display_wm = *cursor_wm = 0; + return false; } - DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n", - planea_wm, planeb_wm, sr_entries); + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + + return g4x_check_srwm(dev, + *display_wm, *cursor_wm, + display, cursor); +} + +static inline bool single_plane_enabled(unsigned int mask) +{ + return mask && (mask & -mask) == 0; +} + +static void g4x_update_wm(struct drm_device *dev) +{ + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, cursora_wm, cursorb_wm; + int plane_sr, cursor_sr; + unsigned int enabled = 0; + + if (g4x_compute_wm0(dev, 0, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1; + + if (g4x_compute_wm0(dev, 1, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 2; + + plane_sr = cursor_sr = 0; + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &g4x_wm_info, + &g4x_cursor_wm_info, + &plane_sr, &cursor_sr)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + else + I915_WRITE(FW_BLC_SELF, + I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); - planea_wm &= 0x3f; - planeb_wm &= 0x3f; + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + plane_sr, cursor_sr); - I915_WRITE(DSPFW1, (sr_entries << DSPFW_SR_SHIFT) | + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | (cursorb_wm << DSPFW_CURSORB_SHIFT) | - (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm); - I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + planea_wm); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | (cursora_wm << DSPFW_CURSORA_SHIFT)); /* HPLL off in SR has some issues on G4x... disable it */ - I915_WRITE(DSPFW3, (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } -static void i965_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size) +static void i965_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long line_time_us; - int sr_clock, sr_entries, srwm = 1; + struct drm_crtc *crtc; + int srwm = 1; int cursor_sr = 16; /* Calc sr entries for one plane configs */ - if (sr_hdisplay && (!planea_clock || !planeb_clock)) { + crtc = single_enabled_crtc(dev); + if (crtc) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 12000; + int clock = crtc->mode.clock; + int htotal = crtc->mode.htotal; + int hdisplay = crtc->mode.hdisplay; + int pixel_size = crtc->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; - sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_htotal * 1000) / sr_clock); + line_time_us = ((htotal * 1000) / clock); /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; - sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE); - DRM_DEBUG("self-refresh entries: %d\n", sr_entries); - srwm = I965_FIFO_SIZE - sr_entries; + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE); + srwm = I965_FIFO_SIZE - entries; if (srwm < 0) srwm = 1; srwm &= 0x1ff; + DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n", + entries, srwm); - sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * pixel_size * 64; - sr_entries = DIV_ROUND_UP(sr_entries, + entries = DIV_ROUND_UP(entries, i965_cursor_wm_info.cacheline_size); cursor_sr = i965_cursor_wm_info.fifo_size - - (sr_entries + i965_cursor_wm_info.guard_size); + (entries + i965_cursor_wm_info.guard_size); if (cursor_sr > i965_cursor_wm_info.max_wm) cursor_sr = i965_cursor_wm_info.max_wm; @@ -3319,46 +3997,56 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, srwm); /* 965 has limitations... */ - I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) | - (8 << 0)); + I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | + (8 << 16) | (8 << 8) | (8 << 0)); I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); /* update cursor SR watermark */ I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } -static void i9xx_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size) +static void i9xx_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + const struct intel_watermark_params *wm_info; uint32_t fwater_lo; uint32_t fwater_hi; - int total_size, cacheline_size, cwm, srwm = 1; + int cwm, srwm = 1; + int fifo_size; int planea_wm, planeb_wm; - struct intel_watermark_params planea_params, planeb_params; - unsigned long line_time_us; - int sr_clock, sr_entries = 0; + struct drm_crtc *crtc, *enabled = NULL; - /* Create copies of the base settings for each pipe */ - if (IS_CRESTLINE(dev) || IS_I945GM(dev)) - planea_params = planeb_params = i945_wm_info; + if (IS_I945GM(dev)) + wm_info = &i945_wm_info; else if (!IS_GEN2(dev)) - planea_params = planeb_params = i915_wm_info; + wm_info = &i915_wm_info; else - planea_params = planeb_params = i855_wm_info; - - /* Grab a couple of global values before we overwrite them */ - total_size = planea_params.fifo_size; - cacheline_size = planea_params.cacheline_size; - - /* Update per-plane FIFO sizes */ - planea_params.fifo_size = dev_priv->display.get_fifo_size(dev, 0); - planeb_params.fifo_size = dev_priv->display.get_fifo_size(dev, 1); + wm_info = &i855_wm_info; + + fifo_size = dev_priv->display.get_fifo_size(dev, 0); + crtc = intel_get_crtc_for_plane(dev, 0); + if (crtc->enabled && crtc->fb) { + planea_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + enabled = crtc; + } else + planea_wm = fifo_size - wm_info->guard_size; + + fifo_size = dev_priv->display.get_fifo_size(dev, 1); + crtc = intel_get_crtc_for_plane(dev, 1); + if (crtc->enabled && crtc->fb) { + planeb_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + if (enabled == NULL) + enabled = crtc; + else + enabled = NULL; + } else + planeb_wm = fifo_size - wm_info->guard_size; - planea_wm = intel_calculate_wm(planea_clock, &planea_params, - pixel_size, latency_ns); - planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params, - pixel_size, latency_ns); DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); /* @@ -3366,39 +4054,39 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, */ cwm = 2; + /* Play safe and disable self-refresh before adjusting watermarks. */ + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); + /* Calc sr entries for one plane configs */ - if (HAS_FW_BLC(dev) && sr_hdisplay && - (!planea_clock || !planeb_clock)) { + if (HAS_FW_BLC(dev) && enabled) { /* self-refresh has much higher latency */ static const int sr_latency_ns = 6000; + int clock = enabled->mode.clock; + int htotal = enabled->mode.htotal; + int hdisplay = enabled->mode.hdisplay; + int pixel_size = enabled->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; - sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_htotal * 1000) / sr_clock); + line_time_us = (htotal * 1000) / clock; /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * sr_hdisplay; - sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); - DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries); - srwm = total_size - sr_entries; + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, wm_info->cacheline_size); + DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); + srwm = wm_info->fifo_size - entries; if (srwm < 0) srwm = 1; if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); - else if (IS_I915GM(dev)) { - /* 915M has a smaller SRWM field */ + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); + else if (IS_I915GM(dev)) I915_WRITE(FW_BLC_SELF, srwm & 0x3f); - I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); - } - } else { - /* Turn off self refresh if both pipes are enabled */ - if (IS_I945G(dev) || IS_I945GM(dev)) { - I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) - & ~FW_BLC_SELF_EN); - } else if (IS_I915GM(dev)) { - I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); - } } DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", @@ -3413,19 +4101,36 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, I915_WRITE(FW_BLC, fwater_lo); I915_WRITE(FW_BLC2, fwater_hi); + + if (HAS_FW_BLC(dev)) { + if (enabled) { + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); + DRM_DEBUG_KMS("memory self refresh enabled\n"); + } else + DRM_DEBUG_KMS("memory self refresh disabled\n"); + } } -static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, - int unused2, int unused3, int pixel_size) +static void i830_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff; + struct drm_crtc *crtc; + uint32_t fwater_lo; int planea_wm; - i830_wm_info.fifo_size = dev_priv->display.get_fifo_size(dev, 0); + crtc = single_enabled_crtc(dev); + if (crtc == NULL) + return; - planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info, - pixel_size, latency_ns); + planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, + dev_priv->display.get_fifo_size(dev, 0), + crtc->fb->bits_per_pixel / 8, + latency_ns); + fwater_lo = I915_READ(FW_BLC) & ~0xfff; fwater_lo |= (3<<8) | planea_wm; DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); @@ -3534,15 +4239,15 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level, /* * Compute watermark values of WM[1-3], */ -static bool ironlake_compute_srwm(struct drm_device *dev, int level, - int hdisplay, int htotal, - int pixel_size, int clock, int latency_ns, +static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, + int latency_ns, const struct intel_watermark_params *display, const struct intel_watermark_params *cursor, int *fbc_wm, int *display_wm, int *cursor_wm) { - + struct drm_crtc *crtc; unsigned long line_time_us; + int hdisplay, htotal, pixel_size, clock; int line_count, line_size; int small, large; int entries; @@ -3552,6 +4257,12 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, return false; } + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + line_time_us = (htotal * 1000) / clock; line_count = (latency_ns / line_time_us + 1000) / 1000; line_size = hdisplay * pixel_size; @@ -3579,14 +4290,11 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, display, cursor); } -static void ironlake_update_wm(struct drm_device *dev, - int planea_clock, int planeb_clock, - int hdisplay, int htotal, - int pixel_size) +static void ironlake_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int fbc_wm, plane_wm, cursor_wm, enabled; - int clock; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; enabled = 0; if (ironlake_compute_wm0(dev, 0, @@ -3600,7 +4308,7 @@ static void ironlake_update_wm(struct drm_device *dev, DRM_DEBUG_KMS("FIFO watermarks For pipe A -" " plane %d, " "cursor: %d\n", plane_wm, cursor_wm); - enabled++; + enabled |= 1; } if (ironlake_compute_wm0(dev, 1, @@ -3614,7 +4322,7 @@ static void ironlake_update_wm(struct drm_device *dev, DRM_DEBUG_KMS("FIFO watermarks For pipe B -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled++; + enabled |= 2; } /* @@ -3625,14 +4333,13 @@ static void ironlake_update_wm(struct drm_device *dev, I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); - if (enabled != 1) + if (!single_plane_enabled(enabled)) return; - - clock = planea_clock ? planea_clock : planeb_clock; + enabled = ffs(enabled) - 1; /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, - clock, ILK_READ_WM1_LATENCY() * 500, + if (!ironlake_compute_srwm(dev, 1, enabled, + ILK_READ_WM1_LATENCY() * 500, &ironlake_display_srwm_info, &ironlake_cursor_srwm_info, &fbc_wm, &plane_wm, &cursor_wm)) @@ -3646,8 +4353,8 @@ static void ironlake_update_wm(struct drm_device *dev, cursor_wm); /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, hdisplay, htotal, pixel_size, - clock, ILK_READ_WM2_LATENCY() * 500, + if (!ironlake_compute_srwm(dev, 2, enabled, + ILK_READ_WM2_LATENCY() * 500, &ironlake_display_srwm_info, &ironlake_cursor_srwm_info, &fbc_wm, &plane_wm, &cursor_wm)) @@ -3666,15 +4373,12 @@ static void ironlake_update_wm(struct drm_device *dev, */ } -static void sandybridge_update_wm(struct drm_device *dev, - int planea_clock, int planeb_clock, - int hdisplay, int htotal, - int pixel_size) +static void sandybridge_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ - int fbc_wm, plane_wm, cursor_wm, enabled; - int clock; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; enabled = 0; if (ironlake_compute_wm0(dev, 0, @@ -3686,7 +4390,7 @@ static void sandybridge_update_wm(struct drm_device *dev, DRM_DEBUG_KMS("FIFO watermarks For pipe A -" " plane %d, " "cursor: %d\n", plane_wm, cursor_wm); - enabled++; + enabled |= 1; } if (ironlake_compute_wm0(dev, 1, @@ -3698,7 +4402,7 @@ static void sandybridge_update_wm(struct drm_device *dev, DRM_DEBUG_KMS("FIFO watermarks For pipe B -" " plane %d, cursor: %d\n", plane_wm, cursor_wm); - enabled++; + enabled |= 2; } /* @@ -3715,14 +4419,13 @@ static void sandybridge_update_wm(struct drm_device *dev, I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); - if (enabled != 1) + if (!single_plane_enabled(enabled)) return; - - clock = planea_clock ? planea_clock : planeb_clock; + enabled = ffs(enabled) - 1; /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, hdisplay, htotal, pixel_size, - clock, SNB_READ_WM1_LATENCY() * 500, + if (!ironlake_compute_srwm(dev, 1, enabled, + SNB_READ_WM1_LATENCY() * 500, &sandybridge_display_srwm_info, &sandybridge_cursor_srwm_info, &fbc_wm, &plane_wm, &cursor_wm)) @@ -3736,9 +4439,8 @@ static void sandybridge_update_wm(struct drm_device *dev, cursor_wm); /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, - hdisplay, htotal, pixel_size, - clock, SNB_READ_WM2_LATENCY() * 500, + if (!ironlake_compute_srwm(dev, 2, enabled, + SNB_READ_WM2_LATENCY() * 500, &sandybridge_display_srwm_info, &sandybridge_cursor_srwm_info, &fbc_wm, &plane_wm, &cursor_wm)) @@ -3752,9 +4454,8 @@ static void sandybridge_update_wm(struct drm_device *dev, cursor_wm); /* WM3 */ - if (!ironlake_compute_srwm(dev, 3, - hdisplay, htotal, pixel_size, - clock, SNB_READ_WM3_LATENCY() * 500, + if (!ironlake_compute_srwm(dev, 3, enabled, + SNB_READ_WM3_LATENCY() * 500, &sandybridge_display_srwm_info, &sandybridge_cursor_srwm_info, &fbc_wm, &plane_wm, &cursor_wm)) @@ -3803,44 +4504,9 @@ static void sandybridge_update_wm(struct drm_device *dev, static void intel_update_watermarks(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - int sr_hdisplay = 0; - unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0; - int enabled = 0, pixel_size = 0; - int sr_htotal = 0; - - if (!dev_priv->display.update_wm) - return; - - /* Get the clock config from both planes */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->active) { - enabled++; - if (intel_crtc->plane == 0) { - DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n", - intel_crtc->pipe, crtc->mode.clock); - planea_clock = crtc->mode.clock; - } else { - DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n", - intel_crtc->pipe, crtc->mode.clock); - planeb_clock = crtc->mode.clock; - } - sr_hdisplay = crtc->mode.hdisplay; - sr_clock = crtc->mode.clock; - sr_htotal = crtc->mode.htotal; - if (crtc->fb) - pixel_size = crtc->fb->bits_per_pixel / 8; - else - pixel_size = 4; /* by default */ - } - } - - if (enabled <= 0) - return; - dev_priv->display.update_wm(dev, planea_clock, planeb_clock, - sr_hdisplay, sr_htotal, pixel_size); + if (dev_priv->display.update_wm) + dev_priv->display.update_wm(dev); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) @@ -3872,6 +4538,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, int ret; struct fdi_m_n m_n = {0}; u32 reg, temp; + u32 lvds_sync = 0; int target_clock; drm_vblank_pre_modeset(dev, pipe); @@ -4243,9 +4910,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_DOUBLE_WIDE; } - dspcntr |= DISPLAY_PLANE_ENABLE; - pipeconf |= PIPECONF_ENABLE; - dpll |= DPLL_VCO_ENABLE; + if (!HAS_PCH_SPLIT(dev)) + dpll |= DPLL_VCO_ENABLE; DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); drm_mode_debug_printmodeline(mode); @@ -4271,10 +4937,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, /* enable transcoder DPLL */ if (HAS_PCH_CPT(dev)) { temp = I915_READ(PCH_DPLL_SEL); - if (pipe == 0) + switch (pipe) { + case 0: temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL; - else + break; + case 1: temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL; + break; + case 2: + /* FIXME: manage transcoder PLLs? */ + temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL; + break; + default: + BUG(); + } I915_WRITE(PCH_DPLL_SEL, temp); POSTING_READ(PCH_DPLL_SEL); @@ -4324,6 +5000,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, else temp &= ~LVDS_ENABLE_DITHER; } + if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) + lvds_sync |= LVDS_HSYNC_POLARITY; + if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) + lvds_sync |= LVDS_VSYNC_POLARITY; + if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) + != lvds_sync) { + char flags[2] = "-+"; + DRM_INFO("Changing LVDS panel from " + "(%chsync, %cvsync) to (%chsync, %cvsync)\n", + flags[!(temp & LVDS_HSYNC_POLARITY)], + flags[!(temp & LVDS_VSYNC_POLARITY)], + flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], + flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + temp |= lvds_sync; + } I915_WRITE(reg, temp); } @@ -4341,17 +5033,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, intel_dp_set_m_n(crtc, mode, adjusted_mode); } else if (HAS_PCH_SPLIT(dev)) { /* For non-DP output, clear any trans DP clock recovery setting.*/ - if (pipe == 0) { - I915_WRITE(TRANSA_DATA_M1, 0); - I915_WRITE(TRANSA_DATA_N1, 0); - I915_WRITE(TRANSA_DP_LINK_M1, 0); - I915_WRITE(TRANSA_DP_LINK_N1, 0); - } else { - I915_WRITE(TRANSB_DATA_M1, 0); - I915_WRITE(TRANSB_DATA_N1, 0); - I915_WRITE(TRANSB_DP_LINK_M1, 0); - I915_WRITE(TRANSB_DP_LINK_N1, 0); - } + I915_WRITE(TRANSDATA_M1(pipe), 0); + I915_WRITE(TRANSDATA_N1(pipe), 0); + I915_WRITE(TRANSDPLINK_M1(pipe), 0); + I915_WRITE(TRANSDPLINK_N1(pipe), 0); } if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { @@ -4454,6 +5139,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); + if (!HAS_PCH_SPLIT(dev)) + intel_enable_pipe(dev_priv, pipe, false); intel_wait_for_vblank(dev, pipe); @@ -4464,6 +5151,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, } I915_WRITE(DSPCNTR(plane), dspcntr); + POSTING_READ(DSPCNTR(plane)); + if (!HAS_PCH_SPLIT(dev)) + intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); @@ -4480,7 +5170,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) 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 palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; + int palreg = PALETTE(intel_crtc->pipe); int i; /* The clocks have to be on to load the palette. */ @@ -4489,8 +5179,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) /* use legacy palette for Ironlake */ if (HAS_PCH_SPLIT(dev)) - palreg = (intel_crtc->pipe == 0) ? LGC_PALETTE_A : - LGC_PALETTE_B; + palreg = LGC_PALETTE(intel_crtc->pipe); for (i = 0; i < 256; i++) { I915_WRITE(palreg + 4 * i, @@ -4511,12 +5200,12 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) if (intel_crtc->cursor_visible == visible) return; - cntl = I915_READ(CURACNTR); + cntl = I915_READ(_CURACNTR); if (visible) { /* On these chipsets we can only modify the base whilst * the cursor is disabled. */ - I915_WRITE(CURABASE, base); + I915_WRITE(_CURABASE, base); cntl &= ~(CURSOR_FORMAT_MASK); /* XXX width must be 64, stride 256 => 0x00 << 28 */ @@ -4525,7 +5214,7 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base) CURSOR_FORMAT_ARGB; } else cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); - I915_WRITE(CURACNTR, cntl); + I915_WRITE(_CURACNTR, cntl); intel_crtc->cursor_visible = visible; } @@ -4539,7 +5228,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) bool visible = base != 0; if (intel_crtc->cursor_visible != visible) { - uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); + uint32_t cntl = I915_READ(CURCNTR(pipe)); if (base) { cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; @@ -4548,12 +5237,12 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); cntl |= CURSOR_MODE_DISABLE; } - I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); + I915_WRITE(CURCNTR(pipe), cntl); intel_crtc->cursor_visible = visible; } /* and commit changes on next vblank */ - I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); + I915_WRITE(CURBASE(pipe), base); } /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ @@ -4603,7 +5292,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, if (!visible && !intel_crtc->cursor_visible) return; - I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos); + I915_WRITE(CURPOS(pipe), pos); if (IS_845G(dev) || IS_I865G(dev)) i845_update_cursor(crtc, base); else @@ -4643,7 +5332,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, } obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle)); - if (!obj) + if (&obj->base == NULL) return -ENOENT; if (obj->base.size < width * height * 4) { @@ -4909,14 +5598,14 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); + u32 dpll = I915_READ(DPLL(pipe)); u32 fp; intel_clock_t clock; if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = I915_READ((pipe == 0) ? FPA0 : FPB0); + fp = FP0(pipe); else - fp = I915_READ((pipe == 0) ? FPA1 : FPB1); + fp = FP1(pipe); clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; if (IS_PINEVIEW(dev)) { @@ -4998,10 +5687,10 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; struct drm_display_mode *mode; - int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); - int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); - int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); - int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); + int htot = I915_READ(HTOTAL(pipe)); + int hsync = I915_READ(HSYNC(pipe)); + int vtot = I915_READ(VTOTAL(pipe)); + int vsync = I915_READ(VSYNC(pipe)); mode = kzalloc(sizeof(*mode), GFP_KERNEL); if (!mode) @@ -5110,7 +5799,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dpll_reg = DPLL(pipe); int dpll = I915_READ(dpll_reg); if (HAS_PCH_SPLIT(dev)) @@ -5158,7 +5847,6 @@ static void intel_idle_update(struct work_struct *work) struct drm_device *dev = dev_priv->dev; struct drm_crtc *crtc; struct intel_crtc *intel_crtc; - int enabled = 0; if (!i915_powersave) return; @@ -5172,16 +5860,11 @@ static void intel_idle_update(struct work_struct *work) if (!crtc->fb) continue; - enabled++; intel_crtc = to_intel_crtc(crtc); if (!intel_crtc->busy) intel_decrease_pllclock(crtc); } - if ((enabled == 1) && (IS_I945G(dev) || IS_I945GM(dev))) { - DRM_DEBUG_DRIVER("enable memory self refresh on 945\n"); - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); - } mutex_unlock(&dev->struct_mutex); } @@ -5206,17 +5889,9 @@ void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) if (!drm_core_check_feature(dev, DRIVER_MODESET)) return; - if (!dev_priv->busy) { - if (IS_I945G(dev) || IS_I945GM(dev)) { - u32 fw_blc_self; - - DRM_DEBUG_DRIVER("disable memory self refresh on 945\n"); - fw_blc_self = I915_READ(FW_BLC_SELF); - fw_blc_self &= ~FW_BLC_SELF_EN; - I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK); - } + if (!dev_priv->busy) dev_priv->busy = true; - } else + else mod_timer(&dev_priv->idle_timer, jiffies + msecs_to_jiffies(GPU_IDLE_TIMEOUT)); @@ -5228,14 +5903,6 @@ void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj) intel_fb = to_intel_framebuffer(crtc->fb); if (intel_fb->obj == obj) { if (!intel_crtc->busy) { - if (IS_I945G(dev) || IS_I945GM(dev)) { - u32 fw_blc_self; - - DRM_DEBUG_DRIVER("disable memory self refresh on 945\n"); - fw_blc_self = I915_READ(FW_BLC_SELF); - fw_blc_self &= ~FW_BLC_SELF_EN; - I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK); - } /* Non-busy -> busy, upclock */ intel_increase_pllclock(crtc); intel_crtc->busy = true; @@ -5513,7 +6180,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, * pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; */ pf = 0; - pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff; + pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); break; @@ -5523,8 +6190,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, OUT_RING(fb->pitch | obj->tiling_mode); OUT_RING(obj->gtt_offset); - pf = I915_READ(pipe == 0 ? PFA_CTL_1 : PFB_CTL_1) & PF_ENABLE; - pipesrc = I915_READ(pipe == 0 ? PIPEASRC : PIPEBSRC) & 0x0fff0fff; + pf = I915_READ(PF_CTL(pipe)) & PF_ENABLE; + pipesrc = I915_READ(PIPESRC(pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); break; } @@ -5558,9 +6225,7 @@ static void intel_crtc_reset(struct drm_crtc *crtc) /* Reset flags back to the 'unknown' status so that they * will be correctly set on the initial modeset. */ - intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = -1; - intel_crtc->active = true; /* force the pipe off on setup_init_config */ } static struct drm_crtc_helper_funcs intel_helper_funcs = { @@ -5615,22 +6280,8 @@ static void intel_sanitize_modesetting(struct drm_device *dev, pipe = !pipe; /* Disable the plane and wait for it to stop reading from the pipe. */ - I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); - intel_flush_display_plane(dev, plane); - - if (IS_GEN2(dev)) - intel_wait_for_vblank(dev, pipe); - - if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE)) - return; - - /* Switch off the pipe. */ - reg = PIPECONF(pipe); - val = I915_READ(reg); - if (val & PIPECONF_ENABLE) { - I915_WRITE(reg, val & ~PIPECONF_ENABLE); - intel_wait_for_pipe_off(dev, pipe); - } + intel_disable_plane(dev_priv, plane, pipe); + intel_disable_pipe(dev_priv, pipe); } static void intel_crtc_init(struct drm_device *dev, int pipe) @@ -5666,6 +6317,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; intel_crtc_reset(&intel_crtc->base); + intel_crtc->active = true; /* force the pipe off on setup_init_config */ if (HAS_PCH_SPLIT(dev)) { intel_helper_funcs.prepare = ironlake_crtc_prepare; @@ -5919,7 +6571,7 @@ intel_user_framebuffer_create(struct drm_device *dev, int ret; obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle)); - if (!obj) + if (&obj->base == NULL) return ERR_PTR(-ENOENT); intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); @@ -6204,7 +6856,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) * userspace... */ I915_WRITE(GEN6_RC_STATE, 0); - __gen6_force_wake_get(dev_priv); + __gen6_gt_force_wake_get(dev_priv); /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -6241,18 +6893,18 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, 18 << 24 | 6 << 16); - I915_WRITE(GEN6_RP_UP_THRESHOLD, 90000); - I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 100000); + I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); I915_WRITE(GEN6_RP_UP_EI, 100000); - I915_WRITE(GEN6_RP_DOWN_EI, 300000); + I915_WRITE(GEN6_RP_DOWN_EI, 5000000); I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO | GEN6_RP_USE_NORMAL_FREQ | GEN6_RP_MEDIA_IS_GFX | GEN6_RP_ENABLE | - GEN6_RP_UP_BUSY_MAX | - GEN6_RP_DOWN_BUSY_MIN); + GEN6_RP_UP_BUSY_AVG | + GEN6_RP_DOWN_IDLE_CONT); if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500)) @@ -6302,12 +6954,13 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) /* enable all PM interrupts */ I915_WRITE(GEN6_PMINTRMSK, 0); - __gen6_force_wake_put(dev_priv); + __gen6_gt_force_wake_put(dev_priv); } void intel_enable_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; /* * Disable clock gating reported to work incorrectly according to the @@ -6417,12 +7070,10 @@ void intel_enable_clock_gating(struct drm_device *dev) ILK_DPARB_CLK_GATE | ILK_DPFD_CLK_GATE); - I915_WRITE(DSPACNTR, - I915_READ(DSPACNTR) | - DISPPLANE_TRICKLE_FEED_DISABLE); - I915_WRITE(DSPBCNTR, - I915_READ(DSPBCNTR) | - DISPPLANE_TRICKLE_FEED_DISABLE); + for_each_pipe(pipe) + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); } } else if (IS_G4X(dev)) { uint32_t dspclk_gate; @@ -6463,52 +7114,60 @@ void intel_enable_clock_gating(struct drm_device *dev) } } -void intel_disable_clock_gating(struct drm_device *dev) +static void ironlake_teardown_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->renderctx) { - struct drm_i915_gem_object *obj = dev_priv->renderctx; - - I915_WRITE(CCID, 0); - POSTING_READ(CCID); - - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); dev_priv->renderctx = NULL; } if (dev_priv->pwrctx) { - struct drm_i915_gem_object *obj = dev_priv->pwrctx; + i915_gem_object_unpin(dev_priv->pwrctx); + drm_gem_object_unreference(&dev_priv->pwrctx->base); + dev_priv->pwrctx = NULL; + } +} + +static void ironlake_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_READ(PWRCTXA)) { + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), + 50); I915_WRITE(PWRCTXA, 0); POSTING_READ(PWRCTXA); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - dev_priv->pwrctx = NULL; + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + POSTING_READ(RSTDBYCTL); } + + ironlake_teardown_rc6(dev); } -static void ironlake_disable_rc6(struct drm_device *dev) +static int ironlake_setup_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); - wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), - 10); - POSTING_READ(CCID); - I915_WRITE(PWRCTXA, 0); - POSTING_READ(PWRCTXA); - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - POSTING_READ(RSTDBYCTL); - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(&dev_priv->pwrctx->base); - dev_priv->pwrctx = NULL; + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (!dev_priv->renderctx) + return -ENOMEM; + + if (dev_priv->pwrctx == NULL) + dev_priv->pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->pwrctx) { + ironlake_teardown_rc6(dev); + return -ENOMEM; + } + + return 0; } void ironlake_enable_rc6(struct drm_device *dev) @@ -6516,15 +7175,26 @@ void ironlake_enable_rc6(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + /* rc6 disabled by default due to repeated reports of hanging during + * boot and resume. + */ + if (!i915_enable_rc6) + return; + + ret = ironlake_setup_rc6(dev); + if (ret) + return; + /* * GPU can automatically power down the render unit if given a page * to save state. */ ret = BEGIN_LP_RING(6); if (ret) { - ironlake_disable_rc6(dev); + ironlake_teardown_rc6(dev); return; } + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); OUT_RING(MI_SET_CONTEXT); OUT_RING(dev_priv->renderctx->gtt_offset | @@ -6541,6 +7211,7 @@ void ironlake_enable_rc6(struct drm_device *dev) I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); } + /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { @@ -6757,10 +7428,6 @@ void intel_modeset_init(struct drm_device *dev) } dev->mode_config.fb_base = dev->agp->base; - if (IS_MOBILE(dev) || !IS_GEN2(dev)) - dev_priv->num_pipe = 2; - else - dev_priv->num_pipe = 1; DRM_DEBUG_KMS("%d display pipe%s available.\n", dev_priv->num_pipe, dev_priv->num_pipe > 1 ? "s" : ""); @@ -6783,21 +7450,9 @@ void intel_modeset_init(struct drm_device *dev) if (IS_GEN6(dev)) gen6_enable_rps(dev_priv); - if (IS_IRONLAKE_M(dev)) { - dev_priv->renderctx = intel_alloc_context_page(dev); - if (!dev_priv->renderctx) - goto skip_rc6; - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (!dev_priv->pwrctx) { - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - goto skip_rc6; - } + if (IS_IRONLAKE_M(dev)) ironlake_enable_rc6(dev); - } -skip_rc6: INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, (unsigned long)dev); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1f4242b682c..d29e33f815d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -49,6 +49,7 @@ struct intel_dp { uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]; bool has_audio; int force_audio; + uint32_t color_range; int dpms_mode; uint8_t link_bw; uint8_t lane_count; @@ -685,6 +686,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int lane_count = 4, bpp = 24; struct intel_dp_m_n m_n; + int pipe = intel_crtc->pipe; /* * Find the lane count in the intel_encoder private @@ -715,39 +717,19 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, mode->clock, adjusted_mode->clock, &m_n); if (HAS_PCH_SPLIT(dev)) { - if (intel_crtc->pipe == 0) { - I915_WRITE(TRANSA_DATA_M1, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n); - I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m); - I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n); - } else { - I915_WRITE(TRANSB_DATA_M1, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n); - I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m); - I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n); - } + I915_WRITE(TRANSDATA_M1(pipe), + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(TRANSDATA_N1(pipe), m_n.gmch_n); + I915_WRITE(TRANSDPLINK_M1(pipe), m_n.link_m); + I915_WRITE(TRANSDPLINK_N1(pipe), m_n.link_n); } else { - if (intel_crtc->pipe == 0) { - I915_WRITE(PIPEA_GMCH_DATA_M, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(PIPEA_GMCH_DATA_N, - m_n.gmch_n); - I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); - I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); - } else { - I915_WRITE(PIPEB_GMCH_DATA_M, - ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | - m_n.gmch_m); - I915_WRITE(PIPEB_GMCH_DATA_N, - m_n.gmch_n); - I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); - I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); - } + I915_WRITE(PIPE_GMCH_DATA_M(pipe), + ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | + m_n.gmch_m); + I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n.gmch_n); + I915_WRITE(PIPE_DP_LINK_M(pipe), m_n.link_m); + I915_WRITE(PIPE_DP_LINK_N(pipe), m_n.link_n); } } @@ -760,8 +742,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_dp->DP = (DP_VOLTAGE_0_4 | - DP_PRE_EMPHASIS_0); + intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; + intel_dp->DP |= intel_dp->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; @@ -813,6 +795,40 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } +static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + /* + * If the panel wasn't on, make sure there's not a currently + * active PP sequence before enabling AUX VDD. + */ + if (!(I915_READ(PCH_PP_STATUS) & PP_ON)) + msleep(dev_priv->panel_t3); + + pp = I915_READ(PCH_PP_CONTROL); + pp |= EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); +} + +static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 pp; + + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + + /* Make sure sequencer is idle before allowing subsequent activity */ + msleep(dev_priv->panel_t12); +} + /* Returns true if the panel was already on when called */ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) { @@ -834,11 +850,6 @@ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); - /* Ouch. We need to wait here for some panels, like Dell e6510 - * https://bugs.freedesktop.org/show_bug.cgi?id=29278i - */ - msleep(300); - if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask, 5000)) DRM_ERROR("panel on wait timed out: 0x%08x\n", @@ -875,11 +886,6 @@ static void ironlake_edp_panel_off (struct drm_device *dev) pp |= PANEL_POWER_RESET; /* restore panel reset bit */ I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); - - /* Ouch. We need to wait here for some panels, like Dell e6510 - * https://bugs.freedesktop.org/show_bug.cgi?id=29278i - */ - msleep(300); } static void ironlake_edp_backlight_on (struct drm_device *dev) @@ -945,7 +951,7 @@ static void intel_dp_prepare(struct drm_encoder *encoder) if (is_edp(intel_dp)) { ironlake_edp_backlight_off(dev); - ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_off(dev); if (!is_pch_edp(intel_dp)) ironlake_edp_pll_on(encoder); else @@ -959,10 +965,15 @@ static void intel_dp_commit(struct drm_encoder *encoder) struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; + if (is_edp(intel_dp)) + ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_start_link_train(intel_dp); - if (is_edp(intel_dp)) + if (is_edp(intel_dp)) { ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp); + } intel_dp_complete_link_train(intel_dp); @@ -988,9 +999,13 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ironlake_edp_pll_off(encoder); } else { if (is_edp(intel_dp)) - ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_on(intel_dp); if (!(dp_reg & DP_PORT_EN)) { intel_dp_start_link_train(intel_dp); + if (is_edp(intel_dp)) { + ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp); + } intel_dp_complete_link_train(intel_dp); } if (is_edp(intel_dp)) @@ -1508,9 +1523,13 @@ ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; - /* Can't disconnect eDP */ - if (is_edp(intel_dp)) - return connector_status_connected; + /* Can't disconnect eDP, but you can close the lid... */ + if (is_edp(intel_dp)) { + status = intel_panel_detect(intel_dp->base.base.dev); + if (status == connector_status_unknown) + status = connector_status_connected; + return status; + } status = connector_status_disconnected; if (intel_dp_aux_native_read(intel_dp, @@ -1639,11 +1658,30 @@ static int intel_dp_get_modes(struct drm_connector *connector) return 0; } +static bool +intel_dp_detect_audio(struct drm_connector *connector) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct edid *edid; + bool has_audio = false; + + edid = drm_get_edid(connector, &intel_dp->adapter); + if (edid) { + has_audio = drm_detect_monitor_audio(edid); + + connector->display_info.raw_edid = NULL; + kfree(edid); + } + + return has_audio; +} + static int intel_dp_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { + struct drm_i915_private *dev_priv = connector->dev->dev_private; struct intel_dp *intel_dp = intel_attached_dp(connector); int ret; @@ -1652,17 +1690,31 @@ intel_dp_set_property(struct drm_connector *connector, return ret; if (property == intel_dp->force_audio_property) { - if (val == intel_dp->force_audio) + int i = val; + bool has_audio; + + if (i == intel_dp->force_audio) return 0; - intel_dp->force_audio = val; + intel_dp->force_audio = i; - if (val > 0 && intel_dp->has_audio) + if (i == 0) + has_audio = intel_dp_detect_audio(connector); + else + has_audio = i > 0; + + if (has_audio == intel_dp->has_audio) return 0; - if (val < 0 && !intel_dp->has_audio) + + intel_dp->has_audio = has_audio; + goto done; + } + + if (property == dev_priv->broadcast_rgb_property) { + if (val == !!intel_dp->color_range) return 0; - intel_dp->has_audio = val > 0; + intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; goto done; } @@ -1785,6 +1837,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_dp->force_audio_property->values[1] = 1; drm_connector_attach_property(connector, intel_dp->force_audio_property, 0); } + + intel_attach_broadcast_rgb_property(connector); } void @@ -1802,6 +1856,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) if (!intel_dp) return; + intel_dp->output_reg = output_reg; + intel_dp->dpms_mode = -1; + intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { kfree(intel_dp); @@ -1841,10 +1898,6 @@ intel_dp_init(struct drm_device *dev, int output_reg) connector->interlace_allowed = true; connector->doublescan_allowed = 0; - intel_dp->output_reg = output_reg; - intel_dp->has_audio = false; - intel_dp->dpms_mode = DRM_MODE_DPMS_ON; - drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs); @@ -1882,21 +1935,33 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { int ret; - bool was_on; + u32 pp_on, pp_div; + + pp_on = I915_READ(PCH_PP_ON_DELAYS); + pp_div = I915_READ(PCH_PP_DIVISOR); - was_on = ironlake_edp_panel_on(intel_dp); + /* Get T3 & T12 values (note: VESA not bspec terminology) */ + dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16; + dev_priv->panel_t3 /= 10; /* t3 in 100us units */ + dev_priv->panel_t12 = pp_div & 0xf; + dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ + + ironlake_edp_panel_vdd_on(intel_dp); ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, intel_dp->dpcd, sizeof(intel_dp->dpcd)); + ironlake_edp_panel_vdd_off(intel_dp); if (ret == sizeof(intel_dp->dpcd)) { if (intel_dp->dpcd[0] >= 0x11) dev_priv->no_aux_handshake = intel_dp->dpcd[3] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING; } else { + /* if this fails, presume the device is a ghost */ DRM_ERROR("failed to retrieve link info\n"); + intel_dp_destroy(&intel_connector->base); + intel_dp_encoder_destroy(&intel_dp->base.base); + return; } - if (!was_on) - ironlake_edp_panel_off(dev); } intel_encoder->hot_plug = intel_dp_hot_plug; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 74db2557d64..5daa991cb28 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -217,6 +217,13 @@ intel_get_crtc_for_pipe(struct drm_device *dev, int pipe) return dev_priv->pipe_to_crtc_mapping[pipe]; } +static inline struct drm_crtc * +intel_get_crtc_for_plane(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return dev_priv->plane_to_crtc_mapping[plane]; +} + struct intel_unpin_work { struct work_struct work; struct drm_device *dev; @@ -230,6 +237,8 @@ struct intel_unpin_work { int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter); extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus); +extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector); + extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg); void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); @@ -260,6 +269,7 @@ extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); extern void intel_panel_setup_backlight(struct drm_device *dev); extern void intel_panel_enable_backlight(struct drm_device *dev); extern void intel_panel_disable_backlight(struct drm_device *dev); +extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_encoder_prepare (struct drm_encoder *encoder); @@ -298,7 +308,6 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); extern void intel_enable_clock_gating(struct drm_device *dev); -extern void intel_disable_clock_gating(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern void gen6_enable_rps(struct drm_i915_private *dev_priv); @@ -322,8 +331,7 @@ extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane); extern void intel_setup_overlay(struct drm_device *dev); extern void intel_cleanup_overlay(struct drm_device *dev); -extern int intel_overlay_switch_off(struct intel_overlay *overlay, - bool interruptible); +extern int intel_overlay_switch_off(struct intel_overlay *overlay); extern int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int intel_overlay_attrs(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index ea373283c93..6eda1b51c63 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -178,7 +178,7 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, int pipe = intel_crtc->pipe; u32 dvo_val; u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; - int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; + int dpll_reg = DPLL(pipe); switch (dvo_reg) { case DVOA: diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 0d0273e7b02..f289b864297 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -41,6 +41,7 @@ struct intel_hdmi { struct intel_encoder base; u32 sdvox_reg; int ddc_bus; + uint32_t color_range; bool has_hdmi_sink; bool has_audio; int force_audio; @@ -124,6 +125,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, u32 sdvox; sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; + sdvox |= intel_hdmi->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) sdvox |= SDVO_VSYNC_ACTIVE_HIGH; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) @@ -251,12 +253,34 @@ static int intel_hdmi_get_modes(struct drm_connector *connector) &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); } +static bool +intel_hdmi_detect_audio(struct drm_connector *connector) +{ + struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct edid *edid; + bool has_audio = false; + + edid = drm_get_edid(connector, + &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter); + if (edid) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) + has_audio = drm_detect_monitor_audio(edid); + + connector->display_info.raw_edid = NULL; + kfree(edid); + } + + return has_audio; +} + static int intel_hdmi_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; int ret; ret = drm_connector_property_set_value(connector, property, val); @@ -264,17 +288,31 @@ intel_hdmi_set_property(struct drm_connector *connector, return ret; if (property == intel_hdmi->force_audio_property) { - if (val == intel_hdmi->force_audio) + int i = val; + bool has_audio; + + if (i == intel_hdmi->force_audio) return 0; - intel_hdmi->force_audio = val; + intel_hdmi->force_audio = i; + + if (i == 0) + has_audio = intel_hdmi_detect_audio(connector); + else + has_audio = i > 0; - if (val > 0 && intel_hdmi->has_audio) + if (has_audio == intel_hdmi->has_audio) return 0; - if (val < 0 && !intel_hdmi->has_audio) + + intel_hdmi->has_audio = has_audio; + goto done; + } + + if (property == dev_priv->broadcast_rgb_property) { + if (val == !!intel_hdmi->color_range) return 0; - intel_hdmi->has_audio = val > 0; + intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; goto done; } @@ -336,6 +374,8 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c intel_hdmi->force_audio_property->values[1] = 1; drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0); } + + intel_attach_broadcast_rgb_property(connector); } void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 58040f68ed7..82d04c5899d 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -384,7 +384,8 @@ int intel_setup_gmbus(struct drm_device *dev) bus->reg0 = i | GMBUS_RATE_100KHZ; /* XXX force bit banging until GMBUS is fully debugged */ - bus->force_bit = intel_gpio_create(dev_priv, i); + if (IS_GEN2(dev)) + bus->force_bit = intel_gpio_create(dev_priv, i); } intel_i2c_reset(dev_priv->dev); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ace8d5d30dd..1a311ad0111 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -231,6 +231,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct intel_lvds *intel_lvds = to_intel_lvds(encoder); struct drm_encoder *tmp_encoder; u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; + int pipe; /* Should never happen!! */ if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) { @@ -261,12 +262,6 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, return true; } - /* Make sure pre-965s set dither correctly */ - if (INTEL_INFO(dev)->gen < 4) { - if (dev_priv->lvds_dither) - pfit_control |= PANEL_8TO6_DITHER_ENABLE; - } - /* Native modes don't need fitting */ if (adjusted_mode->hdisplay == mode->hdisplay && adjusted_mode->vdisplay == mode->vdisplay) @@ -283,8 +278,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * to register description and PRM. * Change the value here to see the borders for debugging */ - I915_WRITE(BCLRPAT_A, 0); - I915_WRITE(BCLRPAT_B, 0); + for_each_pipe(pipe) + I915_WRITE(BCLRPAT(pipe), 0); switch (intel_lvds->fitting_mode) { case DRM_MODE_SCALE_CENTER: @@ -374,10 +369,16 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, } out: + /* If not enabling scaling, be consistent and always use 0. */ if ((pfit_control & PFIT_ENABLE) == 0) { pfit_control = 0; pfit_pgm_ratios = 0; } + + /* Make sure pre-965 set dither correctly */ + if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither) + pfit_control |= PANEL_8TO6_DITHER_ENABLE; + if (pfit_control != intel_lvds->pfit_control || pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) { intel_lvds->pfit_control = pfit_control; @@ -474,6 +475,10 @@ intel_lvds_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; enum drm_connector_status status = connector_status_connected; + status = intel_panel_detect(dev); + if (status != connector_status_unknown) + return status; + /* ACPI lid methods were generally unreliable in this generation, so * don't even bother. */ @@ -496,7 +501,7 @@ static int intel_lvds_get_modes(struct drm_connector *connector) return drm_add_edid_modes(connector, intel_lvds->edid); mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode); - if (mode == 0) + if (mode == NULL) return 0; drm_mode_probed_add(connector, mode); diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c index f70b7cf32bf..9034dd8f33c 100644 --- a/drivers/gpu/drm/i915/intel_modes.c +++ b/drivers/gpu/drm/i915/intel_modes.c @@ -80,3 +80,33 @@ int intel_ddc_get_modes(struct drm_connector *connector, return ret; } + +static const char *broadcast_rgb_names[] = { + "Full", + "Limited 16:235", +}; + +void +intel_attach_broadcast_rgb_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_property *prop; + int i; + + prop = dev_priv->broadcast_rgb_property; + if (prop == NULL) { + prop = drm_property_create(dev, DRM_MODE_PROP_ENUM, + "Broadcast RGB", + ARRAY_SIZE(broadcast_rgb_names)); + if (prop == NULL) + return; + + for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++) + drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]); + + dev_priv->broadcast_rgb_property = prop; + } + + drm_connector_attach_property(connector, prop, 0); +} diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 64fd64443ca..d2c71042290 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -39,6 +39,8 @@ #define OPREGION_HEADER_OFFSET 0 #define OPREGION_ACPI_OFFSET 0x100 +#define ACPI_CLID 0x01ac /* current lid state indicator */ +#define ACPI_CDCK 0x01b0 /* current docking state indicator */ #define OPREGION_SWSCI_OFFSET 0x200 #define OPREGION_ASLE_OFFSET 0x300 #define OPREGION_VBT_OFFSET 0x400 @@ -489,6 +491,8 @@ int intel_opregion_setup(struct drm_device *dev) opregion->header = base; opregion->vbt = base + OPREGION_VBT_OFFSET; + opregion->lid_state = base + ACPI_CLID; + mboxes = opregion->header->mboxes; if (mboxes & MBOX_ACPI) { DRM_DEBUG_DRIVER("Public ACPI methods supported\n"); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3fbb98b948d..a670c006982 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -213,7 +213,6 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay, static int intel_overlay_do_wait_request(struct intel_overlay *overlay, struct drm_i915_gem_request *request, - bool interruptible, void (*tail)(struct intel_overlay *)) { struct drm_device *dev = overlay->dev; @@ -221,16 +220,14 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, int ret; BUG_ON(overlay->last_flip_req); - ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv)); + ret = i915_add_request(LP_RING(dev_priv), NULL, request); if (ret) { kfree(request); return ret; } overlay->last_flip_req = request->seqno; overlay->flip_tail = tail; - ret = i915_do_wait_request(dev, - overlay->last_flip_req, true, - LP_RING(dev_priv)); + ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req); if (ret) return ret; @@ -256,7 +253,7 @@ i830_activate_pipe_a(struct drm_device *dev) return 0; /* most i8xx have pipe a forced on, so don't trust dpms mode */ - if (I915_READ(PIPEACONF) & PIPECONF_ENABLE) + if (I915_READ(_PIPEACONF) & PIPECONF_ENABLE) return 0; crtc_funcs = crtc->base.helper_private; @@ -322,7 +319,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - ret = intel_overlay_do_wait_request(overlay, request, true, NULL); + ret = intel_overlay_do_wait_request(overlay, request, NULL); out: if (pipe_a_quirk) i830_deactivate_pipe_a(dev); @@ -364,7 +361,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, OUT_RING(flip_addr); ADVANCE_LP_RING(); - ret = i915_add_request(dev, NULL, request, LP_RING(dev_priv)); + ret = i915_add_request(LP_RING(dev_priv), NULL, request); if (ret) { kfree(request); return ret; @@ -401,8 +398,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay) } /* overlay needs to be disabled in OCMD reg */ -static int intel_overlay_off(struct intel_overlay *overlay, - bool interruptible) +static int intel_overlay_off(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -437,14 +433,13 @@ static int intel_overlay_off(struct intel_overlay *overlay, OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); ADVANCE_LP_RING(); - return intel_overlay_do_wait_request(overlay, request, interruptible, + return intel_overlay_do_wait_request(overlay, request, intel_overlay_off_tail); } /* recover from an interruption due to a signal * We have to be careful not to repeat work forever an make forward progess. */ -static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, - bool interruptible) +static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay) { struct drm_device *dev = overlay->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -453,8 +448,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay, if (overlay->last_flip_req == 0) return 0; - ret = i915_do_wait_request(dev, overlay->last_flip_req, - interruptible, LP_RING(dev_priv)); + ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req); if (ret) return ret; @@ -499,7 +493,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) OUT_RING(MI_NOOP); ADVANCE_LP_RING(); - ret = intel_overlay_do_wait_request(overlay, request, true, + ret = intel_overlay_do_wait_request(overlay, request, intel_overlay_release_old_vid_tail); if (ret) return ret; @@ -868,8 +862,7 @@ out_unpin: return ret; } -int intel_overlay_switch_off(struct intel_overlay *overlay, - bool interruptible) +int intel_overlay_switch_off(struct intel_overlay *overlay) { struct overlay_registers *regs; struct drm_device *dev = overlay->dev; @@ -878,7 +871,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay, BUG_ON(!mutex_is_locked(&dev->struct_mutex)); BUG_ON(!mutex_is_locked(&dev->mode_config.mutex)); - ret = intel_overlay_recover_from_interrupt(overlay, interruptible); + ret = intel_overlay_recover_from_interrupt(overlay); if (ret != 0) return ret; @@ -893,7 +886,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay, regs->OCMD = 0; intel_overlay_unmap_regs(overlay, regs); - ret = intel_overlay_off(overlay, interruptible); + ret = intel_overlay_off(overlay); if (ret != 0) return ret; @@ -1135,7 +1128,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->struct_mutex); - ret = intel_overlay_switch_off(overlay, true); + ret = intel_overlay_switch_off(overlay); mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->mode_config.mutex); @@ -1157,7 +1150,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, new_bo = to_intel_bo(drm_gem_object_lookup(dev, file_priv, put_image_rec->bo_handle)); - if (!new_bo) { + if (&new_bo->base == NULL) { ret = -ENOENT; goto out_free; } @@ -1171,13 +1164,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, goto out_unlock; } - ret = intel_overlay_recover_from_interrupt(overlay, true); + ret = intel_overlay_recover_from_interrupt(overlay); if (ret != 0) goto out_unlock; if (overlay->crtc != crtc) { struct drm_display_mode *mode = &crtc->base.mode; - ret = intel_overlay_switch_off(overlay, true); + ret = intel_overlay_switch_off(overlay); if (ret != 0) goto out_unlock; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index c65992df458..18391b3ec2c 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -30,8 +30,6 @@ #include "intel_drv.h" -#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ - void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -112,19 +110,6 @@ done: dev_priv->pch_pf_size = (width << 16) | height; } -static int is_backlight_combination_mode(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (INTEL_INFO(dev)->gen >= 4) - return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; - - if (IS_GEN2(dev)) - return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; - - return 0; -} - static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) { u32 val; @@ -181,9 +166,6 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 4) max &= ~1; } - - if (is_backlight_combination_mode(dev)) - max *= 0xff; } DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); @@ -201,15 +183,6 @@ u32 intel_panel_get_backlight(struct drm_device *dev) val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; if (IS_PINEVIEW(dev)) val >>= 1; - - if (is_backlight_combination_mode(dev)){ - u8 lbpc; - - val &= ~1; - pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); - val *= lbpc; - val >>= 1; - } } DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); @@ -232,16 +205,6 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) if (HAS_PCH_SPLIT(dev)) return intel_pch_panel_set_backlight(dev, level); - - if (is_backlight_combination_mode(dev)){ - u32 max = intel_panel_get_max_backlight(dev); - u8 lpbc; - - lpbc = level * 0xfe / max + 1; - level /= lpbc; - pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc); - } - tmp = I915_READ(BLC_PWM_CTL); if (IS_PINEVIEW(dev)) { tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); @@ -281,3 +244,22 @@ void intel_panel_setup_backlight(struct drm_device *dev) dev_priv->backlight_level = intel_panel_get_backlight(dev); dev_priv->backlight_enabled = dev_priv->backlight_level != 0; } + +enum drm_connector_status +intel_panel_detect(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (i915_panel_ignore_lid) + return i915_panel_ignore_lid > 0 ? + connector_status_connected : + connector_status_disconnected; + + /* Assume that the BIOS does not lie through the OpRegion... */ + if (dev_priv->opregion.lid_state) + return ioread32(dev_priv->opregion.lid_state) & 0x1 ? + connector_status_connected : + connector_status_disconnected; + + return connector_status_unknown; +} diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6218fa97aa1..789c47801ba 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -62,18 +62,9 @@ render_ring_flush(struct intel_ring_buffer *ring, u32 flush_domains) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; u32 cmd; int ret; -#if WATCH_EXEC - DRM_INFO("%s: invalidate %08x flush %08x\n", __func__, - invalidate_domains, flush_domains); -#endif - - trace_i915_gem_request_flush(dev, dev_priv->next_seqno, - invalidate_domains, flush_domains); - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { /* * read/write caches: @@ -122,9 +113,6 @@ render_ring_flush(struct intel_ring_buffer *ring, (IS_G4X(dev) || IS_GEN5(dev))) cmd |= MI_INVALIDATE_ISP; -#if WATCH_EXEC - DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd); -#endif ret = intel_ring_begin(ring, 2); if (ret) return ret; @@ -612,7 +600,6 @@ ring_add_request(struct intel_ring_buffer *ring, intel_ring_emit(ring, MI_USER_INTERRUPT); intel_ring_advance(ring); - DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); *result = seqno; return 0; } @@ -715,11 +702,8 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 len) { struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; int ret; - trace_i915_gem_request_submit(dev, dev_priv->next_seqno + 1); - if (IS_I830(dev) || IS_845G(dev)) { ret = intel_ring_begin(ring, 4); if (ret) @@ -894,6 +878,10 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring) /* Disable the ring buffer. The ring must be idle at this point */ dev_priv = ring->dev->dev_private; ret = intel_wait_ring_buffer(ring, ring->size - 8); + if (ret) + DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n", + ring->name, ret); + I915_WRITE_CTL(ring, 0); drm_core_ioremapfree(&ring->map, ring->dev); @@ -950,13 +938,13 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return 0; } - trace_i915_ring_wait_begin (dev); + trace_i915_ring_wait_begin(ring); end = jiffies + 3 * HZ; do { ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); if (ring->space >= n) { - trace_i915_ring_wait_end(dev); + trace_i915_ring_wait_end(ring); return 0; } @@ -970,16 +958,20 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) if (atomic_read(&dev_priv->mm.wedged)) return -EAGAIN; } while (!time_after(jiffies, end)); - trace_i915_ring_wait_end (dev); + trace_i915_ring_wait_end(ring); return -EBUSY; } int intel_ring_begin(struct intel_ring_buffer *ring, int num_dwords) { + struct drm_i915_private *dev_priv = ring->dev->dev_private; int n = 4*num_dwords; int ret; + if (unlikely(atomic_read(&dev_priv->mm.wedged))) + return -EIO; + if (unlikely(ring->tail + n > ring->effective_size)) { ret = intel_wrap_ring_buffer(ring); if (unlikely(ret)) @@ -1059,22 +1051,25 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, } static int gen6_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + u32 invalidate, u32 flush) { + uint32_t cmd; int ret; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0) return 0; ret = intel_ring_begin(ring, 4); if (ret) return ret; - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); + cmd = MI_FLUSH_DW; + if (invalidate & I915_GEM_GPU_DOMAINS) + cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD; + intel_ring_emit(ring, cmd); intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); return 0; } @@ -1230,22 +1225,25 @@ static int blt_ring_begin(struct intel_ring_buffer *ring, } static int blt_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) + u32 invalidate, u32 flush) { + uint32_t cmd; int ret; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0) return 0; ret = blt_ring_begin(ring, 4); if (ret) return ret; - intel_ring_emit(ring, MI_FLUSH_DW); - intel_ring_emit(ring, 0); + cmd = MI_FLUSH_DW; + if (invalidate & I915_GEM_DOMAIN_RENDER) + cmd |= MI_INVALIDATE_TLB; + intel_ring_emit(ring, cmd); intel_ring_emit(ring, 0); intel_ring_emit(ring, 0); + intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 6d6fde85a63..f23cc5f037a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -14,22 +14,23 @@ struct intel_hw_status_page { struct drm_i915_gem_object *obj; }; -#define I915_RING_READ(reg) i915_safe_read(dev_priv, reg) +#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg) +#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val) #define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base)) -#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val) +#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val) #define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base)) -#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val) +#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val) #define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD((ring)->mmio_base)) -#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val) +#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val) #define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base)) -#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val) +#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val) -#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) #define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base)) +#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val) #define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base)) #define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base)) @@ -43,7 +44,7 @@ struct intel_ring_buffer { RING_BLT = 0x4, } id; u32 mmio_base; - void *virtual_start; + void __iomem *virtual_start; struct drm_device *dev; struct drm_i915_gem_object *obj; @@ -58,6 +59,7 @@ struct intel_ring_buffer { u32 irq_refcount; u32 irq_mask; u32 irq_seqno; /* last seq seem at irq time */ + u32 trace_irq_seqno; u32 waiting_seqno; u32 sync_seqno[I915_NUM_RINGS-1]; bool __must_check (*irq_get)(struct intel_ring_buffer *ring); @@ -141,6 +143,26 @@ intel_read_status_page(struct intel_ring_buffer *ring, return ioread32(ring->status_page.page_addr + reg); } +/** + * Reads a dword out of the status page, which is written to from the command + * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or + * MI_STORE_DATA_IMM. + * + * The following dwords have a reserved meaning: + * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes. + * 0x04: ring 0 head pointer + * 0x05: ring 1 head pointer (915-class) + * 0x06: ring 2 head pointer (915-class) + * 0x10-0x1b: Context status DWords (GM45) + * 0x1f: Last written status offset. (GM45) + * + * The area from dword 0x20 to 0x3ff is available for driver usage. + */ +#define READ_HWSP(dev_priv, reg) intel_read_status_page(LP_RING(dev_priv), reg) +#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) +#define I915_GEM_HWS_INDEX 0x20 +#define I915_BREADCRUMB_INDEX 0x21 + void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n); int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); @@ -166,6 +188,12 @@ int intel_init_blt_ring_buffer(struct drm_device *dev); u32 intel_ring_get_active_head(struct intel_ring_buffer *ring); void intel_ring_setup_status_page(struct intel_ring_buffer *ring); +static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno) +{ + if (ring->trace_irq_seqno == 0 && ring->irq_get(ring)) + ring->trace_irq_seqno = seqno; +} + /* DRI warts */ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 318f398e6b2..4324f33212d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -46,6 +46,7 @@ SDVO_TV_MASK) #define IS_TV(c) (c->output_flag & SDVO_TV_MASK) +#define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) @@ -92,6 +93,12 @@ struct intel_sdvo { uint16_t attached_output; /** + * This is used to select the color range of RBG outputs in HDMI mode. + * It is only valid when using TMDS encoding and 8 bit per color mode. + */ + uint32_t color_range; + + /** * This is set if we're going to treat the device as TV-out. * * While we have these nice friendly flags for output types that ought @@ -584,6 +591,7 @@ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *i { struct intel_sdvo_get_trained_inputs_response response; + BUILD_BUG_ON(sizeof(response) != 1); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, &response, sizeof(response))) return false; @@ -631,6 +639,7 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo { struct intel_sdvo_pixel_clock_range clocks; + BUILD_BUG_ON(sizeof(clocks) != 4); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, &clocks, sizeof(clocks))) @@ -698,6 +707,8 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { + BUILD_BUG_ON(sizeof(dtd->part1) != 8); + BUILD_BUG_ON(sizeof(dtd->part2) != 8); return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, &dtd->part1, sizeof(dtd->part1)) && intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, @@ -795,6 +806,7 @@ static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_encode encode; + BUILD_BUG_ON(sizeof(encode) != 2); return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, &encode, sizeof(encode)); @@ -1050,6 +1062,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the SDVO control regs. */ if (INTEL_INFO(dev)->gen >= 4) { sdvox = 0; + if (intel_sdvo->is_hdmi) + sdvox |= intel_sdvo->color_range; if (INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_BORDER_ENABLE; if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) @@ -1161,6 +1175,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { + BUILD_BUG_ON(sizeof(*caps) != 8); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps))) @@ -1267,33 +1282,9 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) static bool intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) { - int caps = 0; - - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) - caps++; - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) - caps++; - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1)) - caps++; - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) - caps++; - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1)) - caps++; - - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1)) - caps++; - - if (intel_sdvo->caps.output_flags & - (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) - caps++; - - return (caps > 1); + /* Is there more than one type of output? */ + int caps = intel_sdvo->caps.output_flags & 0xf; + return caps & -caps; } static struct edid * @@ -1359,7 +1350,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector) intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); } - } + } else + status = connector_status_disconnected; connector->display_info.raw_edid = NULL; kfree(edid); } @@ -1407,10 +1399,25 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; - else if (response & SDVO_TMDS_MASK) + else if (IS_TMDS(intel_sdvo_connector)) ret = intel_sdvo_hdmi_sink_detect(connector); - else - ret = connector_status_connected; + else { + struct edid *edid; + + /* if we have an edid check it matches the connection */ + edid = intel_sdvo_get_edid(connector); + if (edid == NULL) + edid = intel_sdvo_get_analog_edid(connector); + if (edid != NULL) { + if (edid->input & DRM_EDID_INPUT_DIGITAL) + ret = connector_status_disconnected; + else + ret = connector_status_connected; + connector->display_info.raw_edid = NULL; + kfree(edid); + } else + ret = connector_status_connected; + } /* May update encoder flag for like clock for SDVO TV, etc.*/ if (ret == connector_status_connected) { @@ -1446,10 +1453,15 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) edid = intel_sdvo_get_analog_edid(connector); if (edid != NULL) { - if (edid->input & DRM_EDID_INPUT_DIGITAL) { + struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector); + + if (connector_is_digital == monitor_is_digital) { drm_mode_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } + connector->display_info.raw_edid = NULL; kfree(edid); } @@ -1668,6 +1680,22 @@ static void intel_sdvo_destroy(struct drm_connector *connector) kfree(connector); } +static bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector) +{ + struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); + struct edid *edid; + bool has_audio = false; + + if (!intel_sdvo->is_hdmi) + return false; + + edid = intel_sdvo_get_edid(connector); + if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL) + has_audio = drm_detect_monitor_audio(edid); + + return has_audio; +} + static int intel_sdvo_set_property(struct drm_connector *connector, struct drm_property *property, @@ -1675,6 +1703,7 @@ intel_sdvo_set_property(struct drm_connector *connector, { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); + struct drm_i915_private *dev_priv = connector->dev->dev_private; uint16_t temp_value; uint8_t cmd; int ret; @@ -1684,17 +1713,31 @@ intel_sdvo_set_property(struct drm_connector *connector, return ret; if (property == intel_sdvo_connector->force_audio_property) { - if (val == intel_sdvo_connector->force_audio) + int i = val; + bool has_audio; + + if (i == intel_sdvo_connector->force_audio) return 0; - intel_sdvo_connector->force_audio = val; + intel_sdvo_connector->force_audio = i; + + if (i == 0) + has_audio = intel_sdvo_detect_hdmi_audio(connector); + else + has_audio = i > 0; - if (val > 0 && intel_sdvo->has_hdmi_audio) + if (has_audio == intel_sdvo->has_hdmi_audio) return 0; - if (val < 0 && !intel_sdvo->has_hdmi_audio) + + intel_sdvo->has_hdmi_audio = has_audio; + goto done; + } + + if (property == dev_priv->broadcast_rgb_property) { + if (val == !!intel_sdvo->color_range) return 0; - intel_sdvo->has_hdmi_audio = val > 0; + intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; goto done; } @@ -2002,6 +2045,9 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) drm_connector_attach_property(&connector->base.base, connector->force_audio_property, 0); } + + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) + intel_attach_broadcast_rgb_property(&connector->base.base); } static bool @@ -2224,6 +2270,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_set_target_output(intel_sdvo, type)) return false; + BUILD_BUG_ON(sizeof(format) != 6); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, &format, sizeof(format))) @@ -2430,6 +2477,8 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, uint16_t response; } enhancements; + BUILD_BUG_ON(sizeof(enhancements) != 2); + enhancements.response = 0; intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS, diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 93206e4eaa6..4256b8ef394 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1006,6 +1006,7 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, const struct video_levels *video_levels; const struct color_conversion *color_conversion; bool burst_ena; + int pipe = intel_crtc->pipe; if (!tv_mode) return; /* can't happen (mode_prepare prevents this) */ @@ -1149,14 +1150,11 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { - int pipeconf_reg = (intel_crtc->pipe == 0) ? - PIPEACONF : PIPEBCONF; - int dspcntr_reg = (intel_crtc->plane == 0) ? - DSPACNTR : DSPBCNTR; + int pipeconf_reg = PIPECONF(pipe); + int dspcntr_reg = DSPCNTR(pipe); int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = (intel_crtc->plane == 0) ? - DSPAADDR : DSPBADDR; + int dspbase_reg = DSPADDR(pipe); int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ @@ -1234,7 +1232,8 @@ static const struct drm_display_mode reported_modes[] = { * \return false if TV is disconnected. */ static int -intel_tv_detect_type (struct intel_tv *intel_tv) +intel_tv_detect_type (struct intel_tv *intel_tv, + struct drm_connector *connector) { struct drm_encoder *encoder = &intel_tv->base.base; struct drm_device *dev = encoder->dev; @@ -1245,11 +1244,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv) int type; /* Disable TV interrupts around load detect or we'll recurse */ - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_disable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + if (connector->polled & DRM_CONNECTOR_POLL_HPD) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_disable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } save_tv_dac = tv_dac = I915_READ(TV_DAC); save_tv_ctl = tv_ctl = I915_READ(TV_CTL); @@ -1302,11 +1303,13 @@ intel_tv_detect_type (struct intel_tv *intel_tv) I915_WRITE(TV_CTL, save_tv_ctl); /* Restore interrupt config */ - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - i915_enable_pipestat(dev_priv, 0, - PIPE_HOTPLUG_INTERRUPT_ENABLE | - PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + if (connector->polled & DRM_CONNECTOR_POLL_HPD) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + i915_enable_pipestat(dev_priv, 0, + PIPE_HOTPLUG_INTERRUPT_ENABLE | + PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } return type; } @@ -1356,7 +1359,7 @@ intel_tv_detect(struct drm_connector *connector, bool force) drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) { - type = intel_tv_detect_type(intel_tv); + type = intel_tv_detect_type(intel_tv, connector); } else if (force) { struct drm_crtc *crtc; int dpms_mode; @@ -1364,7 +1367,7 @@ intel_tv_detect(struct drm_connector *connector, bool force) crtc = intel_get_load_detect_pipe(&intel_tv->base, connector, &mode, &dpms_mode); if (crtc) { - type = intel_tv_detect_type(intel_tv); + type = intel_tv_detect_type(intel_tv, connector); intel_release_load_detect_pipe(&intel_tv->base, connector, dpms_mode); } else @@ -1658,6 +1661,18 @@ intel_tv_init(struct drm_device *dev) intel_encoder = &intel_tv->base; connector = &intel_connector->base; + /* The documentation, for the older chipsets at least, recommend + * using a polling method rather than hotplug detection for TVs. + * This is because in order to perform the hotplug detection, the PLLs + * for the TV must be kept alive increasing power drain and starving + * bandwidth from other encoders. Notably for instance, it causes + * pipe underruns on Crestline when this encoder is supposedly idle. + * + * More recent chipsets favour HDMI rather than integrated S-Video. + */ + connector->polled = + DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); |