From a12cbf8aa5cf21d30bd2c798ff059cb1ba92b382 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 30 May 2008 18:20:01 -0400 Subject: RADEON: fix typo in last commit --- shared-core/radeon_cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 819a61ae..5675fda6 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -127,7 +127,7 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi); } else { - RADEON_WRITE(RADEON_MC_AGP_LOCATION, agp_base_lo); + RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200) RADEON_WRITE(RADEON_AGP_BASE_2, agp_base_hi); } -- cgit v1.2.3 From 2186f9f6eff4b3b4f605d35a030c0910646865ab Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 12:49:20 -0400 Subject: [FreeBSD] Call drm_vblank_cleanup during irq uninstall I needed to re-arrange some functions for this. Also needed to call DRM_SPINUNINIT on the vbl_lock during cleanup. --- bsd-core/drm_irq.c | 287 +++++++++++++++++++++++++++-------------------------- 1 file changed, 145 insertions(+), 142 deletions(-) diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 592e2ea8..4b10ba4f 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -66,6 +66,116 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS) } #endif +static void vblank_disable_fn(void *arg) +{ + struct drm_device *dev = (struct drm_device *)arg; + unsigned long irqflags; + int i; + + for (i = 0; i < dev->num_crtcs; i++) { + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + if (atomic_read(&dev->vblank_refcount[i]) == 0 && + dev->vblank_enabled[i]) { + dev->driver.disable_vblank(dev, i); + dev->vblank_enabled[i] = 0; + } + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + } +} + +static void drm_vblank_cleanup(struct drm_device *dev) +{ + /* Bail if the driver didn't call drm_vblank_init() */ + if (dev->num_crtcs == 0) + return; + + callout_drain(&dev->vblank_disable_timer); + + vblank_disable_fn((void *)dev); + DRM_SPINUNINIT(&dev->vbl_lock); + + drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, + DRM_MEM_DRIVER); + drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * + dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, + DRM_MEM_DRIVER); + + dev->num_crtcs = 0; +} + +int drm_vblank_init(struct drm_device *dev, int num_crtcs) +{ + int i, ret = -ENOMEM; + + callout_init(&dev->vblank_disable_timer, 0); + DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); + atomic_set(&dev->vbl_signal_pending, 0); + dev->num_crtcs = num_crtcs; + + dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vbl_queue) + goto err; + + dev->vbl_sigs = drm_alloc(sizeof(struct drm_vbl_sig) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vbl_sigs) + goto err; + + dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->_vblank_count) + goto err; + + dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, + DRM_MEM_DRIVER); + if (!dev->vblank_refcount) + goto err; + + dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_enabled) + goto err; + + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + if (!dev->last_vblank) + goto err; + + dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), + DRM_MEM_DRIVER); + if (!dev->vblank_premodeset) + goto err; + + dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + if (!dev->vblank_offset) + goto err; + + /* Zero per-crtc vblank stuff */ + for (i = 0; i < num_crtcs; i++) { + DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); + TAILQ_INIT(&dev->vbl_sigs[i]); + atomic_set(&dev->_vblank_count[i], 0); + atomic_set(&dev->vblank_refcount[i], 0); + } + + return 0; + +err: + drm_vblank_cleanup(dev); + return ret; +} + int drm_irq_install(struct drm_device *dev) { int retcode; @@ -175,6 +285,8 @@ int drm_irq_uninstall(struct drm_device *dev) #elif defined(__NetBSD__) || defined(__OpenBSD__) pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh); #endif + drm_vblank_cleanup(dev); + DRM_SPINUNINIT(&dev->irq_lock); return 0; @@ -208,27 +320,37 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) } } -static void vblank_disable_fn(void *arg) +u32 drm_vblank_count(struct drm_device *dev, int crtc) +{ + return atomic_read(&dev->_vblank_count[crtc]) + + dev->vblank_offset[crtc]; +} + +void drm_update_vblank_count(struct drm_device *dev, int crtc) { - struct drm_device *dev = (struct drm_device *)arg; unsigned long irqflags; - int i; + u32 cur_vblank, diff; - for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank_refcount[i]) == 0 && - dev->vblank_enabled[i]) { - dev->driver.disable_vblank(dev, i); - dev->vblank_enabled[i] = 0; - } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + /* + * Interrupts were disabled prior to this call, so deal with counter + * wrap if needed. + * NOTE! It's possible we lost a full dev->max_vblank_count events + * here if the register is small or we had vblank interrupts off for + * a long time. + */ + cur_vblank = dev->driver.get_vblank_counter(dev, crtc); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + if (cur_vblank < dev->last_vblank[crtc]) { + diff = dev->max_vblank_count - + dev->last_vblank[crtc]; + diff += cur_vblank; + } else { + diff = cur_vblank - dev->last_vblank[crtc]; } -} + dev->last_vblank[crtc] = cur_vblank; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); -u32 drm_vblank_count(struct drm_device *dev, int crtc) -{ - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; + atomic_add(diff, &dev->_vblank_count[crtc]); } int drm_vblank_get(struct drm_device *dev, int crtc) @@ -261,40 +383,6 @@ void drm_vblank_put(struct drm_device *dev, int crtc) (timeout_t *)vblank_disable_fn, (void *)dev); } -void drm_handle_vblank(struct drm_device *dev, int crtc) -{ - drm_update_vblank_count(dev, crtc); - DRM_WAKEUP(&dev->vbl_queue[crtc]); - drm_vbl_send_signals(dev, crtc); -} - -void drm_update_vblank_count(struct drm_device *dev, int crtc) -{ - unsigned long irqflags; - u32 cur_vblank, diff; - - /* - * Interrupts were disabled prior to this call, so deal with counter - * wrap if needed. - * NOTE! It's possible we lost a full dev->max_vblank_count events - * here if the register is small or we had vblank interrupts off for - * a long time. - */ - cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - if (cur_vblank < dev->last_vblank[crtc]) { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } else { - diff = cur_vblank - dev->last_vblank[crtc]; - } - dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); - - atomic_add(diff, &dev->_vblank_count[crtc]); -} - int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -410,98 +498,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr return ret; } -static void drm_vblank_cleanup(struct drm_device *dev) -{ - /* Bail if the driver didn't call drm_vblank_init() */ - if (dev->num_crtcs == 0) - return; - - callout_stop(&dev->vblank_disable_timer); - - vblank_disable_fn((void *)dev); - - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vbl_sigs, sizeof(*dev->vbl_sigs) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); - - dev->num_crtcs = 0; -} - -int drm_vblank_init(struct drm_device *dev, int num_crtcs) -{ - int i, ret = -ENOMEM; - - callout_init(&dev->vblank_disable_timer, 0); - DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); - atomic_set(&dev->vbl_signal_pending, 0); - dev->num_crtcs = num_crtcs; - - dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vbl_queue) - goto err; - - dev->vbl_sigs = drm_alloc(sizeof(struct drm_vbl_sig) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vbl_sigs) - goto err; - - dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->_vblank_count) - goto err; - - dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); - if (!dev->vblank_refcount) - goto err; - - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_enabled) - goto err; - - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->last_vblank) - goto err; - - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) - goto err; - - /* Zero per-crtc vblank stuff */ - for (i = 0; i < num_crtcs; i++) { - DRM_INIT_WAITQUEUE(&dev->vbl_queue[i]); - TAILQ_INIT(&dev->vbl_sigs[i]); - atomic_set(&dev->_vblank_count[i], 0); - atomic_set(&dev->vblank_refcount[i], 0); - } - - return 0; - -err: - drm_vblank_cleanup(dev); - return ret; -} - void drm_vbl_send_signals(struct drm_device *dev, int crtc) { } @@ -530,6 +526,13 @@ void drm_vbl_send_signals(struct drm_device *dev, int crtc ) } #endif +void drm_handle_vblank(struct drm_device *dev, int crtc) +{ + drm_update_vblank_count(dev, crtc); + DRM_WAKEUP(&dev->vbl_queue[crtc]); + drm_vbl_send_signals(dev, crtc); +} + static void drm_locked_task(void *context, int pending __unused) { struct drm_device *dev = context; -- cgit v1.2.3 From ac4da869285173ad0ac947bdf41ffe10efe21c05 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 12:56:34 -0400 Subject: [FreeBSD] Add symlink for radeon_microcode.h --- bsd-core/radeon_microcode.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 bsd-core/radeon_microcode.h diff --git a/bsd-core/radeon_microcode.h b/bsd-core/radeon_microcode.h new file mode 120000 index 00000000..709fff30 --- /dev/null +++ b/bsd-core/radeon_microcode.h @@ -0,0 +1 @@ +../shared-core/radeon_microcode.h \ No newline at end of file -- cgit v1.2.3 From 4ce47fd328cd885d66abdd42db1f7c054bd44498 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 16:17:31 -0400 Subject: [FreeBSD] Get rid of vbl_lock and re-use irq_lock. --- bsd-core/drmP.h | 5 +---- bsd-core/drm_irq.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 4c35cdb2..21cf623a 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -788,11 +788,10 @@ struct drm_device { wait_queue_head_t *vbl_queue; /* vblank wait queue */ atomic_t *_vblank_count; /* number of VBLANK interrupts */ /* (driver must alloc the right number of counters) */ - struct mtx vbl_lock; struct drm_vbl_sig_list *vbl_sigs; /* signal list to send on VBLANK */ atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ - u32 *last_vblank; /* protected by dev->vbl_lock, used */ + u32 *last_vblank; /* protected by dev->irq_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ @@ -802,8 +801,6 @@ struct drm_device { struct callout vblank_disable_timer; unsigned long max_vblank_count; /* size of vblank counter register */ int num_crtcs; - atomic_t vbl_received; - atomic_t vbl_received2; #ifdef __FreeBSD__ struct sigio *buf_sigio; /* Processes waiting for SIGIO */ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 4b10ba4f..57a70263 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -73,13 +73,13 @@ static void vblank_disable_fn(void *arg) int i; for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } } @@ -92,7 +92,6 @@ static void drm_vblank_cleanup(struct drm_device *dev) callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); - DRM_SPINUNINIT(&dev->vbl_lock); drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, DRM_MEM_DRIVER); @@ -119,7 +118,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) int i, ret = -ENOMEM; callout_init(&dev->vblank_disable_timer, 0); - DRM_SPININIT(&dev->vbl_lock, "drm_vblk"); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -339,7 +337,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { diff = dev->max_vblank_count - dev->last_vblank[crtc]; @@ -348,7 +346,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -358,7 +356,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ atomic_add_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 1 && @@ -369,7 +367,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) else dev->vblank_enabled[crtc] = 1; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); return ret; } -- cgit v1.2.3 From 416754f1cc5a55b1c6b2d2fa2f501b18462d62e6 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 1 Jun 2008 19:34:29 -0400 Subject: [FreeBSD] Declare vblank_disable_fn callout MPSAFE. --- bsd-core/drm_irq.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 57a70263..b76e96dd 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -72,23 +72,40 @@ static void vblank_disable_fn(void *arg) unsigned long irqflags; int i; + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + if (callout_pending(&dev->vblank_disable_timer)) { + /* callout was reset */ + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + return; + } + if (!callout_active(&dev->vblank_disable_timer)) { + /* callout was stopped */ + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + return; + } + callout_deactivate(&dev->vblank_disable_timer); + for (i = 0; i < dev->num_crtcs; i++) { - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) { + unsigned long irqflags; + /* Bail if the driver didn't call drm_vblank_init() */ if (dev->num_crtcs == 0) return; + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + callout_stop(&dev->vblank_disable_timer); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); @@ -117,7 +134,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - callout_init(&dev->vblank_disable_timer, 0); + callout_init_mtx(&dev->vblank_disable_timer, &dev->irq_lock, 1); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -374,11 +391,15 @@ int drm_vblank_get(struct drm_device *dev, int crtc) void drm_vblank_put(struct drm_device *dev, int crtc) { + unsigned long irqflags; + + DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); + DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); } int drm_modeset_ctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From f1e12d40af6ce9b6159c28529bcbdc877c565c82 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Jun 2008 12:40:54 +1000 Subject: drm/ati_pcigart: use proper page mapping function This should be pci_map_page not pci_map_single --- linux-core/ati_pcigart.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 09251ac3..c2aafd22 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -80,7 +80,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info for (i = 0; i < pages; i++) { if (!entry->busaddr[i]) break; - pci_unmap_single(dev->pdev, entry->busaddr[i], + pci_unmap_page(dev->pdev, entry->busaddr[i], PAGE_SIZE, PCI_DMA_TODEVICE); } @@ -143,10 +143,8 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ - entry->busaddr[i] = pci_map_single(dev->pdev, - page_address(entry-> - pagelist[i]), - PAGE_SIZE, PCI_DMA_TODEVICE); + entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], + 0, PAGE_SIZE, PCI_DMA_TODEVICE); if (entry->busaddr[i] == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_pcigart_cleanup(dev, gart_info); -- cgit v1.2.3 From d5ae19ebcf2dc6402872e0575b5786b6e8117b6f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 3 Jun 2008 12:42:49 +1000 Subject: drm: sg alloc should write back the handle to userspace --- shared-core/drm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 52b01cd1..7f1ccd1d 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1020,7 +1020,7 @@ struct drm_mm_info_arg { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, struct drm_agp_binding) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, struct drm_agp_binding) -#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, struct drm_scatter_gather) +#define DRM_IOCTL_SG_ALLOC DRM_IOWR(0x38, struct drm_scatter_gather) #define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather) #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) -- cgit v1.2.3 From 6b520005c6714d8a8afa68b8a43065a40da298cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jun 2008 11:27:39 +0200 Subject: Revert "don't copy back if an error was returned." This reverts commit 6671ad1917698b6174a1af314b63b3800d75248c. The vblank ioctl needs to update the userspace parameters when interrupted by a signal, which was prevented by this. Let's see if this breaks other ioctls... --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b8b8333e..609fc838 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -655,7 +655,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retcode = func(dev, kdata, file_priv); } - if ((retcode == 0) && (cmd & IOC_OUT)) { + if (cmd & IOC_OUT) { if (copy_to_user((void __user *)arg, kdata, _IOC_SIZE(cmd)) != 0) retcode = -EACCES; -- cgit v1.2.3 From 0144ebeb8a713b1420d35004075037cd4b0495a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jun 2008 11:28:09 +0200 Subject: vblank: Don't return current sequence number and time if interrupted by signal. --- linux-core/drm_irq.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 8f27d7f3..e2f106e4 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -484,7 +484,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { union drm_wait_vblank *vblwait = data; - struct timeval now; int ret = 0; unsigned int flags, seq, crtc; @@ -588,11 +587,16 @@ int drm_wait_vblank(struct drm_device *dev, void *data, (((cur_vblank = drm_vblank_count(dev, crtc)) - vblwait->request.sequence) <= (1 << 23))); drm_vblank_put(dev, crtc); - do_gettimeofday(&now); - vblwait->reply.tval_sec = now.tv_sec; - vblwait->reply.tval_usec = now.tv_usec; - vblwait->reply.sequence = cur_vblank; + if (ret != -EINTR) { + struct timeval now; + + do_gettimeofday(&now); + + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + vblwait->reply.sequence = cur_vblank; + } } done: -- cgit v1.2.3 From d1dcb2b32e0c51d7cbcaa2ba1e0544452cf8f47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jun 2008 11:28:09 +0200 Subject: vblank: Special-case driver vblank counter going back by 1. Turns out the radeon driver is affected by the same problem that prompted i915 to revert to less useful counter flipping at the end of the vblank interval. In the long term, we can hopefully implement more reliable methods to achieve counter flipping at the beginning of vblank, but otherwise this should be an acceptable workaround. --- linux-core/drm_irq.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index e2f106e4..ccb3ca89 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -360,9 +360,16 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) cur_vblank = dev->driver->get_vblank_counter(dev, crtc); spin_lock_irqsave(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; + if (cur_vblank == dev->last_vblank[crtc] - 1) { + diff = 0; + } else { + diff = dev->max_vblank_count - + dev->last_vblank[crtc]; + diff += cur_vblank; + } + + DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", + crtc, dev->last_vblank[crtc], cur_vblank, diff); } else { diff = cur_vblank - dev->last_vblank[crtc]; } -- cgit v1.2.3 From 237172b7670611b36d92be3b92983674846f6564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jun 2008 11:28:10 +0200 Subject: vblank: Clean up compensation for spurious wraparounds of driver counter. Only compensate when the driver counter actually appears to have moved backwards. The compensation deltas need to be incremental instead of absolute; drop the vblank_offset field and just use atomic_sub(). --- linux-core/drmP.h | 5 ++--- linux-core/drm_irq.c | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 69d31e14..d7b1960c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -840,13 +840,12 @@ struct drm_device { atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ - u32 *vblank_offset; /* used to track how many vblanks */ int *vblank_enabled; /* so we don't call enable more than once per disable */ - u32 *vblank_premodeset; /* were lost during modeset */ + u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ struct timer_list vblank_disable_timer; - unsigned long max_vblank_count; /**< size of vblank counter register */ + u32 max_vblank_count; /**< size of vblank counter register */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ void (*locked_tasklet_func)(struct drm_device *dev); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index ccb3ca89..3627a890 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -112,8 +112,6 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); dev->num_crtcs = 0; } @@ -162,10 +160,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_premodeset) goto err; - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) - goto err; - /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { init_waitqueue_head(&dev->vbl_queue[i]); @@ -330,8 +324,7 @@ int drm_control(struct drm_device *dev, void *data, */ u32 drm_vblank_count(struct drm_device *dev, int crtc) { - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; + return atomic_read(&dev->_vblank_count[crtc]); } EXPORT_SYMBOL(drm_vblank_count); @@ -457,7 +450,18 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, break; case _DRM_POST_MODESET: new = dev->driver->get_vblank_counter(dev, crtc); - dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; + + /* Compensate for spurious wraparound */ + if (new < dev->vblank_premodeset[crtc]) { + atomic_sub(dev->max_vblank_count + new - + dev->vblank_premodeset[crtc], + &dev->_vblank_count[crtc]); + DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x " + "=> _vblank_count[%d]-=0x%x\n", crtc, + dev->vblank_premodeset[crtc], new, + crtc, dev->max_vblank_count + new - + dev->vblank_premodeset[crtc]); + } break; default: ret = -EINVAL; -- cgit v1.2.3 From ba7263b8c2f8c14c647da725ecbc73fcd456d63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 3 Jun 2008 11:28:10 +0200 Subject: vblank: Don't wait or update the counter while the CRTC is supposedly disabled. Without kernel modesetting, this requires cooperation of the userspace modesetting driver. We may have to leave the vblank interrupt enabled otherwise to avoid problems. --- linux-core/drmP.h | 1 + linux-core/drm_irq.c | 62 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index d7b1960c..00db3000 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -843,6 +843,7 @@ struct drm_device { int *vblank_enabled; /* so we don't call enable more than once per disable */ u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ + int *vblank_suspend; /* Don't wait while crtc is likely disabled */ struct timer_list vblank_disable_timer; u32 max_vblank_count; /**< size of vblank counter register */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 3627a890..abedbe73 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -112,6 +112,8 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; } @@ -160,6 +162,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_premodeset) goto err; + dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_suspend) + goto err; + /* Zero per-crtc vblank stuff */ for (i = 0; i < num_crtcs; i++) { init_waitqueue_head(&dev->vbl_queue[i]); @@ -343,6 +350,9 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) unsigned long irqflags; u32 cur_vblank, diff; + if (dev->vblank_suspend[crtc]) + return; + /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -435,7 +445,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; - u32 new; crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { @@ -447,21 +456,25 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, case _DRM_PRE_MODESET: dev->vblank_premodeset[crtc] = dev->driver->get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; break; case _DRM_POST_MODESET: - new = dev->driver->get_vblank_counter(dev, crtc); - - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) { - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); - DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x " - "=> _vblank_count[%d]-=0x%x\n", crtc, - dev->vblank_premodeset[crtc], new, - crtc, dev->max_vblank_count + new - - dev->vblank_premodeset[crtc]); + if (dev->vblank_suspend[crtc]) { + u32 new = dev->driver->get_vblank_counter(dev, crtc); + + /* Compensate for spurious wraparound */ + if (new < dev->vblank_premodeset[crtc]) { + atomic_sub(dev->max_vblank_count + new - + dev->vblank_premodeset[crtc], + &dev->_vblank_count[crtc]); + DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" + " => _vblank_count[%d]-=0x%x\n", crtc, + dev->vblank_premodeset[crtc], new, + crtc, dev->max_vblank_count + new - + dev->vblank_premodeset[crtc]); + } } + dev->vblank_suspend[crtc] = 0; break; default: ret = -EINVAL; @@ -538,6 +551,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; struct drm_vbl_sig *vbl_sig; + if (dev->vblank_suspend[crtc]) + return -EBUSY; + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -589,15 +605,15 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->reply.sequence = seq; } else { - unsigned long cur_vblank; - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - (((cur_vblank = drm_vblank_count(dev, crtc)) - - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); + if (!dev->vblank_suspend[crtc]) { + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23))); + drm_vblank_put(dev, crtc); + } if (ret != -EINTR) { struct timeval now; @@ -606,7 +622,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; - vblwait->reply.sequence = cur_vblank; + vblwait->reply.sequence = drm_vblank_count(dev, crtc); } } -- cgit v1.2.3 From 6905c7a29d2a3bc0e605a09b98ac02a4a50893d0 Mon Sep 17 00:00:00 2001 From: Dennis Kasprzyk Date: Thu, 5 Jun 2008 17:08:44 +0200 Subject: radeon: Restore software interrupt on resume. Fixes performance drop after suspend/resume on some systems. --- shared-core/radeon_cp.c | 1 + shared-core/radeon_drv.h | 1 + shared-core/radeon_irq.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 5675fda6..75b1dc55 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1296,6 +1296,7 @@ static int radeon_do_resume_cp(struct drm_device * dev) radeon_cp_init_ring_buffer(dev, dev_priv); radeon_do_engine_reset(dev); + radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1); DRM_DEBUG("radeon_do_resume_cp() complete\n"); diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index e263c610..1b59f871 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -375,6 +375,7 @@ extern void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap); /* radeon_irq.c */ +extern void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state); extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index d21761fb..f58d7fa2 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -35,7 +35,7 @@ #include "radeon_drm.h" #include "radeon_drv.h" -static void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) +void radeon_irq_set_state(struct drm_device *dev, u32 mask, int state) { drm_radeon_private_t *dev_priv = dev->dev_private; -- cgit v1.2.3 From fc74c2e9d65dbd0c611e1610886df098c6e3273b Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 2 Jun 2008 13:12:59 -0400 Subject: [FreeBSD] Go back to using vbl_lock and move init/destroy to load/unload. --- bsd-core/drmP.h | 3 ++- bsd-core/drm_drv.c | 7 ++++++- bsd-core/drm_irq.c | 35 +++++++++++++++-------------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 21cf623a..d3f53b86 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -733,6 +733,7 @@ struct drm_device { /* Locks */ #if defined(__FreeBSD__) && __FreeBSD_version > 500000 + struct mtx vbl_lock; /* protects vblank operations */ struct mtx dma_lock; /* protects dev->dma */ struct mtx irq_lock; /* protects irq condition checks */ struct mtx dev_lock; /* protects everything else */ @@ -791,7 +792,7 @@ struct drm_device { struct drm_vbl_sig_list *vbl_sigs; /* signal list to send on VBLANK */ atomic_t vbl_signal_pending; /* number of signals pending on all crtcs*/ atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ - u32 *last_vblank; /* protected by dev->irq_lock, used */ + u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ u32 *vblank_offset; /* used to track how many vblanks */ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 9924ac34..ece00e18 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -202,7 +202,9 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist) DRM_DEV_MODE, "dri/card%d", unit); #if __FreeBSD_version >= 500000 - mtx_init(&dev->dev_lock, "drm device", NULL, MTX_DEF); + mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF); + mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); + mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); #endif @@ -594,6 +596,9 @@ error: #ifdef __FreeBSD__ destroy_dev(dev->devnode); #if __FreeBSD_version >= 500000 + mtx_destroy(&dev->drw_lock); + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->dev_lock); #endif #endif diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index b76e96dd..79f8f9ff 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -72,15 +72,15 @@ static void vblank_disable_fn(void *arg) unsigned long irqflags; int i; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } if (!callout_active(&dev->vblank_disable_timer)) { /* callout was stopped */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } callout_deactivate(&dev->vblank_disable_timer); @@ -92,7 +92,7 @@ static void vblank_disable_fn(void *arg) dev->vblank_enabled[i] = 0; } } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) @@ -103,9 +103,9 @@ static void drm_vblank_cleanup(struct drm_device *dev) if (dev->num_crtcs == 0) return; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); callout_stop(&dev->vblank_disable_timer); - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); @@ -134,7 +134,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = -ENOMEM; - callout_init_mtx(&dev->vblank_disable_timer, &dev->irq_lock, 1); + callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); atomic_set(&dev->vbl_signal_pending, 0); dev->num_crtcs = num_crtcs; @@ -212,8 +212,6 @@ int drm_irq_install(struct drm_device *dev) dev->context_flag = 0; - DRM_SPININIT(&dev->irq_lock, "DRM IRQ lock"); - /* Before installing handler */ dev->driver.irq_preinstall(dev); DRM_UNLOCK(); @@ -268,7 +266,6 @@ err: dev->irqrid = 0; } #endif - DRM_SPINUNINIT(&dev->irq_lock); DRM_UNLOCK(); return retcode; } @@ -302,8 +299,6 @@ int drm_irq_uninstall(struct drm_device *dev) #endif drm_vblank_cleanup(dev); - DRM_SPINUNINIT(&dev->irq_lock); - return 0; } @@ -354,7 +349,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { diff = dev->max_vblank_count - dev->last_vblank[crtc]; @@ -363,7 +358,7 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -373,7 +368,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ atomic_add_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 1 && @@ -384,7 +379,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) else dev->vblank_enabled[crtc] = 1; } - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return ret; } @@ -393,13 +388,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) { unsigned long irqflags; - DRM_SPINLOCK_IRQSAVE(&dev->irq_lock, irqflags); + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); - DRM_SPINUNLOCK_IRQRESTORE(&dev->irq_lock, irqflags); + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } int drm_modeset_ctl(struct drm_device *dev, void *data, @@ -488,9 +483,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr vblwait->reply.sequence = atomic_read(&dev->vbl_received); - DRM_SPINLOCK(&dev->irq_lock); + DRM_SPINLOCK(&dev->vbl_lock); TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link); - DRM_SPINUNLOCK(&dev->irq_lock); + DRM_SPINUNLOCK(&dev->vbl_lock); ret = 0; #endif ret = EINVAL; -- cgit v1.2.3 From 93c57ff4e5d9f62be0a353222fef564dd9e59e39 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 2 Jun 2008 19:35:00 -0400 Subject: [FreeBSD] Remove the locks in the vblank_disable_fn They are recursive and causing panics with witness enabled. --- bsd-core/drm_irq.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 79f8f9ff..132d01bb 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -69,18 +69,14 @@ drm_irq_handler_wrap(DRM_IRQ_ARGS) static void vblank_disable_fn(void *arg) { struct drm_device *dev = (struct drm_device *)arg; - unsigned long irqflags; int i; - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } if (!callout_active(&dev->vblank_disable_timer)) { /* callout was stopped */ - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); return; } callout_deactivate(&dev->vblank_disable_timer); @@ -92,7 +88,6 @@ static void vblank_disable_fn(void *arg) dev->vblank_enabled[i] = 0; } } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } static void drm_vblank_cleanup(struct drm_device *dev) @@ -106,6 +101,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); callout_stop(&dev->vblank_disable_timer); DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + callout_drain(&dev->vblank_disable_timer); vblank_disable_fn((void *)dev); -- cgit v1.2.3 From ec3d9960219e49e1bd24a097e04c3da88e2fcc53 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 13:02:38 -0400 Subject: [FreeBSD] Forgot to call mtx_destroy on all the locks at unload. --- bsd-core/drm_drv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index ece00e18..1616dbb4 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -655,6 +655,9 @@ static void drm_unload(struct drm_device *dev) drm_mem_uninit(); #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 + mtx_destroy(&dev->drw_lock); + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->dev_lock); #endif } -- cgit v1.2.3 From 6d6921719c7d475856199ddbe88bbe11fc882ba6 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 16:21:13 -0400 Subject: [FreeBSD] Incorporate vblank fixes for bsd. --- bsd-core/drmP.h | 7 ++-- bsd-core/drm_irq.c | 93 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index d3f53b86..88ea4e69 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -794,13 +794,12 @@ struct drm_device { atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ - - u32 *vblank_offset; /* used to track how many vblanks */ int *vblank_enabled; /* so we don't call enable more than */ /* once per disable */ - u32 *vblank_premodeset; /* were lost during modeset */ + u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ + int *vblank_suspend; /* Don't wait while crtc is likely disabled */ struct callout vblank_disable_timer; - unsigned long max_vblank_count; /* size of vblank counter register */ + u32 max_vblank_count; /* size of vblank counter register */ int num_crtcs; #ifdef __FreeBSD__ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 132d01bb..c3ecd28b 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -120,15 +120,15 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs, - DRM_MEM_DRIVER); + drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; } int drm_vblank_init(struct drm_device *dev, int num_crtcs) { - int i, ret = -ENOMEM; + int i, ret = ENOMEM; callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); atomic_set(&dev->vbl_signal_pending, 0); @@ -168,8 +168,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_premodeset) goto err; - dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); - if (!dev->vblank_offset) + dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_suspend) goto err; /* Zero per-crtc vblank stuff */ @@ -328,8 +329,7 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) u32 drm_vblank_count(struct drm_device *dev, int crtc) { - return atomic_read(&dev->_vblank_count[crtc]) + - dev->vblank_offset[crtc]; + return atomic_read(&dev->_vblank_count[crtc]); } void drm_update_vblank_count(struct drm_device *dev, int crtc) @@ -337,6 +337,9 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) unsigned long irqflags; u32 cur_vblank, diff; + if (dev->vblank_suspend[crtc]) + return; + /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -347,9 +350,16 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) cur_vblank = dev->driver.get_vblank_counter(dev, crtc); DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; + if (cur_vblank == dev->last_vblank[crtc] - 1) { + diff = 0; + } else { + diff = dev->max_vblank_count - + dev->last_vblank[crtc]; + diff += cur_vblank; + } + + DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", + crtc, dev->last_vblank[crtc], cur_vblank, diff); } else { diff = cur_vblank - dev->last_vblank[crtc]; } @@ -398,11 +408,10 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; - u32 new; crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { - ret = -EINVAL; + ret = EINVAL; goto out; } @@ -410,13 +419,28 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, case _DRM_PRE_MODESET: dev->vblank_premodeset[crtc] = dev->driver.get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; break; case _DRM_POST_MODESET: - new = dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new; + if (dev->vblank_suspend[crtc]) { + u32 new = dev->driver.get_vblank_counter(dev, crtc); + + /* Compensate for spurious wraparound */ + if (new < dev->vblank_premodeset[crtc]) { + atomic_sub(dev->max_vblank_count + new - + dev->vblank_premodeset[crtc], + &dev->_vblank_count[crtc]); + DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" + " => _vblank_count[%d]-=0x%x\n", crtc, + dev->vblank_premodeset[crtc], new, + crtc, dev->max_vblank_count + new - + dev->vblank_premodeset[crtc]); + } + } + dev->vblank_suspend[crtc] = 0; break; default: - ret = -EINVAL; + ret = EINVAL; break; } @@ -427,7 +451,6 @@ out: int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_wait_vblank_t *vblwait = data; - struct timeval now; int ret = 0; int flags, seq, crtc; @@ -473,6 +496,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (vbl_sig == NULL) return ENOMEM; + if (dev->vblank_suspend[crtc]) + return EBUSY; + vbl_sig->sequence = vblwait->request.sequence; vbl_sig->signo = vblwait->request.signal; vbl_sig->pid = DRM_CURRENTPID; @@ -486,23 +512,28 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr #endif ret = EINVAL; } else { - unsigned long cur_vblank; - - DRM_LOCK(); - /* shared code returns -errno */ - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - (((cur_vblank = drm_vblank_count(dev, crtc)) + if (!dev->vblank_suspend[crtc]) { + DRM_LOCK(); + /* shared code returns -errno */ + + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - DRM_UNLOCK(); + drm_vblank_put(dev, crtc); + DRM_UNLOCK(); + } - microtime(&now); - vblwait->reply.tval_sec = now.tv_sec; - vblwait->reply.tval_usec = now.tv_usec; + if (ret != EINTR) { + struct timeval now; + + microtime(&now); + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + vblwait->reply.sequence = drm_vblank_count(dev, crtc); + } } return ret; -- cgit v1.2.3 From 96141bd33c0d6c4b95a2adb668538ffc1103cc18 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 5 Jun 2008 12:46:39 -0400 Subject: [FreeBSD] We need to request busmastering support. This seems to be the key to getting at least some radeon cards working. Most, if not all drivers need it enabled, so just request it once the driver has attached. --- bsd-core/drm_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 1616dbb4..740a8b57 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -544,6 +544,8 @@ static int drm_load(struct drm_device *dev) /* Shared code returns -errno. */ retcode = -dev->driver.load(dev, dev->id_entry->driver_private); + if (pci_enable_busmaster(dev->device)) + DRM_ERROR("Request to enable bus-master failed.\n"); DRM_UNLOCK(); if (retcode != 0) goto error; @@ -654,6 +656,10 @@ static void drm_unload(struct drm_device *dev) delete_unrhdr(dev->drw_unrhdr); drm_mem_uninit(); + + if (pci_disable_busmaster(dev->device)) + DRM_ERROR("Request to disable bus-master failed.\n"); + #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 mtx_destroy(&dev->drw_lock); mtx_destroy(&dev->irq_lock); -- cgit v1.2.3 From 3b6ca4bf3f334341a158a9917ef117c23f145597 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Wed, 4 Jun 2008 15:04:41 -0400 Subject: [FreeBSD] Rework ati_pcigart.c This is mostly just a diff reduction with the linux version. I'm not convinced that it will make anything better. --- bsd-core/ati_pcigart.c | 127 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 39 deletions(-) diff --git a/bsd-core/ati_pcigart.c b/bsd-core/ati_pcigart.c index 2b511ada..f8d3f18d 100644 --- a/bsd-core/ati_pcigart.c +++ b/bsd-core/ati_pcigart.c @@ -34,76 +34,125 @@ #include "drmP.h" #define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ +#define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) + +#define ATI_PCIE_WRITE 0x4 +#define ATI_PCIE_READ 0x8 + +static int drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, + PAGE_SIZE, + gart_info->table_mask); + if (dev->sg->dmah == NULL) + return ENOMEM; + + return 0; +} + +static void drm_ati_free_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + drm_pci_free(dev, dev->sg->dmah); + dev->sg->dmah = NULL; +} + +int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) +{ + /* we need to support large memory configurations */ + if (dev->sg == NULL) { + DRM_ERROR("no scatter/gather memory!\n"); + return 0; + } + + if (gart_info->bus_addr) { + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { + gart_info->bus_addr = 0; + if (dev->sg->dmah) + drm_ati_free_pcigart_table(dev, gart_info); + } + } + + return 1; +} int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { + + void *address = NULL; unsigned long pages; - u32 *pci_gart = NULL, page_base; - int i, j; + u32 *pci_gart, page_base; + dma_addr_t bus_address = 0; + int i, j, ret = 0; + int max_pages; + dma_addr_t entry_addr; + /* we need to support large memory configurations */ if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; + DRM_ERROR("no scatter/gather memory!\n"); + goto done; } if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - /* GART table in system memory */ - dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, 0, - 0xfffffffful); - if (dev->sg->dmah == NULL) { - DRM_ERROR("cannot allocate PCI GART table!\n"); - return 0; + DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); + + ret = drm_ati_alloc_pcigart_table(dev, gart_info); + if (ret) { + DRM_ERROR("cannot allocate PCI GART page!\n"); + goto done; } - - gart_info->addr = (void *)dev->sg->dmah->vaddr; - gart_info->bus_addr = dev->sg->dmah->busaddr; - pci_gart = (u32 *)dev->sg->dmah->vaddr; + + address = (void *)dev->sg->dmah->vaddr; + bus_address = dev->sg->dmah->busaddr; } else { - /* GART table in framebuffer memory */ - pci_gart = gart_info->addr; + address = gart_info->addr; + bus_address = gart_info->bus_addr; + DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", + (unsigned int)bus_address, (unsigned long)address); } - - pages = DRM_MIN(dev->sg->pages, gart_info->table_size / sizeof(u32)); - bzero(pci_gart, gart_info->table_size); + pci_gart = (u32 *) address; - KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (dev->sg->pages <= max_pages) + ? dev->sg->pages : max_pages; + + memset(pci_gart, 0, max_pages * sizeof(u32)); - for ( i = 0 ; i < pages ; i++ ) { - page_base = (u32) dev->sg->busaddr[i]; + KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); + for (i = 0; i < pages; i++) { + entry_addr = dev->sg->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; switch(gart_info->gart_reg_if) { case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32(page_base | 0xc); + page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; + page_base |= 0xc; break; case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + page_base >>= 8; + page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; + page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; break; default: - *pci_gart = cpu_to_le32(page_base); + case DRM_ATI_GART_PCI: break; } + *pci_gart = cpu_to_le32(page_base); pci_gart++; - page_base += ATI_PCIGART_PAGE_SIZE; + entry_addr += ATI_PCIGART_PAGE_SIZE; } } DRM_MEMORYBARRIER(); - return 1; -} - -int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) -{ - if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; - } - - drm_pci_free(dev, dev->sg->dmah); + ret = 1; - return 1; + done: + gart_info->addr = address; + gart_info->bus_addr = bus_address; + return ret; } -- cgit v1.2.3 From d43f3cb0974b635c1a31b839807e5a691c44b4c6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 Jun 2008 05:32:41 +1000 Subject: r300/r500: add hier-z regs --- shared-core/r300_cmdbuf.c | 24 ++--- shared-core/r300_reg.h | 224 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 189 insertions(+), 59 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index bff6378f..e9f99c8f 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -190,7 +190,7 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(0x42C0, 2); ADD_RANGE(R300_RS_CNTL_0, 2); - ADD_RANGE(0x43A4, 2); + ADD_RANGE(R300_SC_HYPERZ, 2); ADD_RANGE(0x43E8, 1); ADD_RANGE(0x46A4, 5); @@ -209,14 +209,12 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(0x4E50, 9); ADD_RANGE(0x4E88, 1); ADD_RANGE(0x4EA0, 2); - ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3); - ADD_RANGE(R300_RB3D_ZSTENCIL_FORMAT, 4); - ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */ - ADD_RANGE(R300_RB3D_DEPTHPITCH, 1); - ADD_RANGE(0x4F28, 1); - ADD_RANGE(0x4F30, 2); - ADD_RANGE(0x4F44, 1); - ADD_RANGE(0x4F54, 1); + ADD_RANGE(R300_ZB_CNTL, 3); + ADD_RANGE(R300_ZB_FORMAT, 4); + ADD_RANGE_MARK(R300_ZB_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */ + ADD_RANGE(R300_ZB_DEPTHPITCH, 1); + ADD_RANGE(R300_ZB_DEPTHCLEARVALUE, 1); + ADD_RANGE(R300_ZB_ZMASK_OFFSET, 13); ADD_RANGE(R300_TX_FILTER_0, 16); ADD_RANGE(R300_TX_FILTER1_0, 16); @@ -229,7 +227,7 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R300_TX_BORDER_COLOR_0, 16); /* Sporadic registers used as primitives are emitted */ - ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1); + ADD_RANGE(R300_ZB_ZCACHE_CTLSTAT, 1); ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1); ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8); ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8); @@ -243,6 +241,7 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(R500_RS_INST_0, 16); ADD_RANGE(R500_RB3D_COLOR_CLEAR_VALUE_AR, 2); ADD_RANGE(R500_RB3D_CONSTANT_COLOR_AR, 2); + ADD_RANGE(R500_ZB_FIFO_SIZE, 2); } else { ADD_RANGE(R300_PFS_CNTL_0, 3); ADD_RANGE(R300_PFS_NODE_0, 4); @@ -720,8 +719,9 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) BEGIN_RING(6); OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A); - OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); - OUT_RING(R300_RB3D_ZCACHE_UNKNOWN_03); + OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); + OUT_RING(R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE| + R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE); OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0)); OUT_RING(0x0); ADVANCE_RING(); diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h index 0be01fc7..1920ab07 100644 --- a/shared-core/r300_reg.h +++ b/shared-core/r300_reg.h @@ -705,6 +705,27 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_RS_ROUTE_1_UNKNOWN11 (1 << 11) /* END: Rasterization / Interpolators - many guesses */ +/* Hierarchical Z Enable */ +#define R300_SC_HYPERZ 0x43a4 +# define R300_SC_HYPERZ_DISABLE (0 << 0) +# define R300_SC_HYPERZ_ENABLE (1 << 0) +# define R300_SC_HYPERZ_MIN (0 << 1) +# define R300_SC_HYPERZ_MAX (1 << 1) +# define R300_SC_HYPERZ_ADJ_256 (0 << 2) +# define R300_SC_HYPERZ_ADJ_128 (1 << 2) +# define R300_SC_HYPERZ_ADJ_64 (2 << 2) +# define R300_SC_HYPERZ_ADJ_32 (3 << 2) +# define R300_SC_HYPERZ_ADJ_16 (4 << 2) +# define R300_SC_HYPERZ_ADJ_8 (5 << 2) +# define R300_SC_HYPERZ_ADJ_4 (6 << 2) +# define R300_SC_HYPERZ_ADJ_2 (7 << 2) +# define R300_SC_HYPERZ_HZ_Z0MIN_NO (0 << 5) +# define R300_SC_HYPERZ_HZ_Z0MIN (1 << 5) +# define R300_SC_HYPERZ_HZ_Z0MAX_NO (0 << 6) +# define R300_SC_HYPERZ_HZ_Z0MAX (1 << 6) + +#define R300_SC_EDGERULE 0x43a8 + /* BEGIN: Scissors and cliprects */ /* There are four clipping rectangles. Their corner coordinates are inclusive. @@ -1358,19 +1379,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * for this. * Bit (1<<8) is the "test" bit. so plain write is 6 - vd */ -#define R300_RB3D_ZSTENCIL_CNTL_0 0x4F00 -# define R300_RB3D_Z_DISABLED_1 0x00000010 -# define R300_RB3D_Z_DISABLED_2 0x00000014 -# define R300_RB3D_Z_TEST 0x00000012 -# define R300_RB3D_Z_TEST_AND_WRITE 0x00000016 -# define R300_RB3D_Z_WRITE_ONLY 0x00000006 - -# define R300_RB3D_Z_TEST 0x00000012 -# define R300_RB3D_Z_TEST_AND_WRITE 0x00000016 -# define R300_RB3D_Z_WRITE_ONLY 0x00000006 -# define R300_RB3D_STENCIL_ENABLE 0x00000001 - -#define R300_RB3D_ZSTENCIL_CNTL_1 0x4F04 +#define R300_ZB_CNTL 0x4F00 +# define R300_STENCIL_ENABLE (1 << 0) +# define R300_Z_ENABLE (1 << 1) +# define R300_Z_WRITE_ENABLE (1 << 2) +# define R300_Z_SIGNED_COMPARE (1 << 3) +# define R300_STENCIL_FRONT_BACK (1 << 4) + +#define R300_ZB_ZSTENCILCNTL 0x4f04 /* functions */ # define R300_ZS_NEVER 0 # define R300_ZS_LESS 1 @@ -1390,52 +1406,166 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. # define R300_ZS_INVERT 5 # define R300_ZS_INCR_WRAP 6 # define R300_ZS_DECR_WRAP 7 +# define R300_Z_FUNC_SHIFT 0 /* front and back refer to operations done for front and back faces, i.e. separate stencil function support */ -# define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT 0 -# define R300_RB3D_ZS1_FRONT_FUNC_SHIFT 3 -# define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT 6 -# define R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT 9 -# define R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT 12 -# define R300_RB3D_ZS1_BACK_FUNC_SHIFT 15 -# define R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT 18 -# define R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT 21 -# define R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT 24 - -#define R300_RB3D_ZSTENCIL_CNTL_2 0x4F08 -# define R300_RB3D_ZS2_STENCIL_REF_SHIFT 0 -# define R300_RB3D_ZS2_STENCIL_MASK 0xFF -# define R300_RB3D_ZS2_STENCIL_MASK_SHIFT 8 -# define R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT 16 +# define R300_S_FRONT_FUNC_SHIFT 3 +# define R300_S_FRONT_SFAIL_OP_SHIFT 6 +# define R300_S_FRONT_ZPASS_OP_SHIFT 9 +# define R300_S_FRONT_ZFAIL_OP_SHIFT 12 +# define R300_S_BACK_FUNC_SHIFT 15 +# define R300_S_BACK_SFAIL_OP_SHIFT 18 +# define R300_S_BACK_ZPASS_OP_SHIFT 21 +# define R300_S_BACK_ZFAIL_OP_SHIFT 24 + +#define R300_ZB_STENCILREFMASK 0x4f08 +# define R300_STENCILREF_SHIFT 0 +# define R300_STENCILREF_MASK 0x000000ff +# define R300_STENCILMASK_SHIFT 8 +# define R300_STENCILMASK_MASK 0x0000ff00 +# define R300_STENCILWRITEMASK_SHIFT 16 +# define R300_STENCILWRITEMASK_MASK 0x00ff0000 /* gap */ -#define R300_RB3D_ZSTENCIL_FORMAT 0x4F10 -# define R300_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) -# define R300_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) - /* 16 bit format or some aditional bit ? */ -# define R300_DEPTH_FORMAT_UNK32 (32 << 0) +#define R300_ZB_FORMAT 0x4f10 +# define R300_DEPTHFORMAT_16BIT_INT_Z (0 << 0) +# define R300_DEPTHFORMAT_16BIT_13E3 (1 << 0) +# define R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL (2 << 0) +/* reserved up to (15 << 0) */ +# define R300_INVERT_13E3_LEADING_ONES (0 << 4) +# define R300_INVERT_13E3_LEADING_ZEROS (1 << 4) -#define R300_RB3D_EARLY_Z 0x4F14 -# define R300_EARLY_Z_DISABLE (0 << 0) -# define R300_EARLY_Z_ENABLE (1 << 0) +#define R300_ZB_ZTOP 0x4F14 +# define R300_ZTOP_DISABLE (0 << 0) +# define R300_ZTOP_ENABLE (1 << 0) /* gap */ -#define R300_RB3D_ZCACHE_CTLSTAT 0x4F18 /* GUESS */ -# define R300_RB3D_ZCACHE_UNKNOWN_01 0x1 -# define R300_RB3D_ZCACHE_UNKNOWN_03 0x3 +#define R300_ZB_ZCACHE_CTLSTAT 0x4f18 +# define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_NO_EFFECT (0 << 0) +# define R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE (1 << 0) +# define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_NO_EFFECT (0 << 1) +# define R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE (1 << 1) +# define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_IDLE (0 << 31) +# define R300_ZB_ZCACHE_CTLSTAT_ZC_BUSY_BUSY (1 << 31) + +#define R300_ZB_BW_CNTL 0x4f1c +# define R300_HIZ_DISABLE (0 << 0) +# define R300_HIZ_ENABLE (1 << 0) +# define R300_HIZ_MIN (0 << 1) +# define R300_HIZ_MAX (1 << 1) +# define R300_FAST_FILL_DISABLE (0 << 2) +# define R300_FAST_FILL_ENABLE (1 << 2) +# define R300_RD_COMP_DISABLE (0 << 3) +# define R300_RD_COMP_ENABLE (1 << 3) +# define R300_WR_COMP_DISABLE (0 << 4) +# define R300_WR_COMP_ENABLE (1 << 4) +# define R300_ZB_CB_CLEAR_RMW (0 << 5) +# define R300_ZB_CB_CLEAR_CACHE_LINEAR (1 << 5) +# define R300_FORCE_COMPRESSED_STENCIL_VALUE_DISABLE (0 << 6) +# define R300_FORCE_COMPRESSED_STENCIL_VALUE_ENABLE (1 << 6) + +# define R500_ZEQUAL_OPTIMIZE_ENABLE (0 << 7) +# define R500_ZEQUAL_OPTIMIZE_DISABLE (1 << 7) +# define R500_SEQUAL_OPTIMIZE_ENABLE (0 << 8) +# define R500_SEQUAL_OPTIMIZE_DISABLE (1 << 8) + +# define R500_BMASK_ENABLE (0 << 10) +# define R500_BMASK_DISABLE (1 << 10) +# define R500_HIZ_EQUAL_REJECT_DISABLE (0 << 11) +# define R500_HIZ_EQUAL_REJECT_ENABLE (1 << 11) +# define R500_HIZ_FP_EXP_BITS_DISABLE (0 << 12) +# define R500_HIZ_FP_EXP_BITS_1 (1 << 12) +# define R500_HIZ_FP_EXP_BITS_2 (2 << 12) +# define R500_HIZ_FP_EXP_BITS_3 (3 << 12) +# define R500_HIZ_FP_EXP_BITS_4 (4 << 12) +# define R500_HIZ_FP_EXP_BITS_5 (5 << 12) +# define R500_HIZ_FP_INVERT_LEADING_ONES (0 << 15) +# define R500_HIZ_FP_INVERT_LEADING_ZEROS (1 << 15) +# define R500_TILE_OVERWRITE_RECOMPRESSION_ENABLE (0 << 16) +# define R500_TILE_OVERWRITE_RECOMPRESSION_DISABLE (1 << 16) +# define R500_CONTIGUOUS_6XAA_SAMPLES_ENABLE (0 << 17) +# define R500_CONTIGUOUS_6XAA_SAMPLES_DISABLE (1 << 17) +# define R500_PEQ_PACKING_DISABLE (0 << 18) +# define R500_PEQ_PACKING_ENABLE (1 << 18) +# define R500_COVERED_PTR_MASKING_DISABLE (0 << 18) +# define R500_COVERED_PTR_MASKING_ENABLE (1 << 18) + /* gap */ -#define R300_RB3D_DEPTHOFFSET 0x4F20 -#define R300_RB3D_DEPTHPITCH 0x4F24 -# define R300_DEPTHPITCH_MASK 0x00001FF8 /* GUESS */ -# define R300_DEPTH_TILE_ENABLE (1 << 16) /* GUESS */ -# define R300_DEPTH_MICROTILE_ENABLE (1 << 17) /* GUESS */ -# define R300_DEPTH_ENDIAN_NO_SWAP (0 << 18) /* GUESS */ -# define R300_DEPTH_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */ -# define R300_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */ +/* Z Buffer Address Offset. + * Bits 31 to 5 are used for aligned Z buffer address offset for macro tiles. + */ +#define R300_ZB_DEPTHOFFSET 0x4f20 + +/* Z Buffer Pitch and Endian Control */ +#define R300_ZB_DEPTHPITCH 0x4f24 +# define R300_DEPTHPITCH_MASK 0x00003FFC +# define R300_DEPTHMACROTILE_DISABLE (0 << 16) +# define R300_DEPTHMACROTILE_ENABLE (1 << 16) +# define R300_DEPTHMICROTILE_LINEAR (0 << 17) +# define R300_DEPTHMICROTILE_TILED (1 << 17) +# define R300_DEPTHMICROTILE_TILED_SQUARE (2 << 17) +# define R300_DEPTHENDIAN_NO_SWAP (0 << 18) +# define R300_DEPTHENDIAN_WORD_SWAP (1 << 18) +# define R300_DEPTHENDIAN_DWORD_SWAP (2 << 18) +# define R300_DEPTHENDIAN_HALF_DWORD_SWAP (3 << 18) + +/* Z Buffer Clear Value */ +#define R300_ZB_DEPTHCLEARVALUE 0x4f28 + +#define R300_ZB_ZMASK_OFFSET 0x4f30 +#define R300_ZB_ZMASK_PITCH 0x4f34 +#define R300_ZB_ZMASK_WRINDEX 0x4f38 +#define R300_ZB_ZMASK_DWORD 0x4f3c +#define R300_ZB_ZMASK_RDINDEX 0x4f40 + +/* Hierarchical Z Memory Offset */ +#define R300_ZB_HIZ_OFFSET 0x4f44 + +/* Hierarchical Z Write Index */ +#define R300_ZB_HIZ_WRINDEX 0x4f48 + +/* Hierarchical Z Data */ +#define R300_ZB_HIZ_DWORD 0x4f4c + +/* Hierarchical Z Read Index */ +#define R300_ZB_HIZ_RDINDEX 0x4f50 + +/* Hierarchical Z Pitch */ +#define R300_ZB_HIZ_PITCH 0x4f54 + +/* Z Buffer Z Pass Counter Data */ +#define R300_ZB_ZPASS_DATA 0x4f58 + +/* Z Buffer Z Pass Counter Address */ +#define R300_ZB_ZPASS_ADDR 0x4f5c + +/* Depth buffer X and Y coordinate offset */ +#define R300_ZB_DEPTHXY_OFFSET 0x4f60 +# define R300_DEPTHX_OFFSET_SHIFT 1 +# define R300_DEPTHX_OFFSET_MASK 0x000007FE +# define R300_DEPTHY_OFFSET_SHIFT 17 +# define R300_DEPTHY_OFFSET_MASK 0x07FE0000 + +/* Sets the fifo sizes */ +#define R500_ZB_FIFO_SIZE 0x4fd0 +# define R500_OP_FIFO_SIZE_FULL (0 << 0) +# define R500_OP_FIFO_SIZE_HALF (1 << 0) +# define R500_OP_FIFO_SIZE_QUATER (2 << 0) +# define R500_OP_FIFO_SIZE_EIGTHS (4 << 0) + +/* Stencil Reference Value and Mask for backfacing quads */ +/* R300_ZB_STENCILREFMASK handles front face */ +#define R500_ZB_STENCILREFMASK_BF 0x4fd4 +# define R500_STENCILREF_SHIFT 0 +# define R500_STENCILREF_MASK 0x000000ff +# define R500_STENCILMASK_SHIFT 8 +# define R500_STENCILMASK_MASK 0x0000ff00 +# define R500_STENCILWRITEMASK_SHIFT 16 +# define R500_STENCILWRITEMASK_MASK 0x00ff0000 /* BEGIN: Vertex program instruction set */ -- cgit v1.2.3 From 116870a908edd8da02381d23694b321e8878f92e Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Tue, 3 Jun 2008 21:15:54 -0400 Subject: I915 suspend/resume for FreeBSD --- bsd-core/i915/Makefile | 2 +- bsd-core/i915_drv.c | 32 ++- bsd-core/i915_suspend.c | 1 + linux-core/Makefile.kernel | 2 +- linux-core/i915_drv.c | 460 +-------------------------------------- linux-core/i915_suspend.c | 1 + shared-core/i915_dma.c | 2 +- shared-core/i915_drv.h | 11 + shared-core/i915_suspend.c | 525 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 574 insertions(+), 462 deletions(-) create mode 120000 bsd-core/i915_suspend.c create mode 120000 linux-core/i915_suspend.c create mode 100644 shared-core/i915_suspend.c diff --git a/bsd-core/i915/Makefile b/bsd-core/i915/Makefile index 6fd7d728..f88155a5 100644 --- a/bsd-core/i915/Makefile +++ b/bsd-core/i915/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/.. KMOD = i915 NO_MAN = YES -SRCS = i915_dma.c i915_drv.c i915_irq.c i915_mem.c +SRCS = i915_dma.c i915_drv.c i915_irq.c i915_mem.c i915_suspend.c SRCS += device_if.h bus_if.h pci_if.h opt_drm.h CFLAGS += ${DEBUG_FLAGS} -I. -I.. diff --git a/bsd-core/i915_drv.c b/bsd-core/i915_drv.c index e6769d17..c19ef5db 100644 --- a/bsd-core/i915_drv.c +++ b/bsd-core/i915_drv.c @@ -40,10 +40,38 @@ static drm_pci_id_list_t i915_pciidlist[] = { i915_PCI_IDS }; +static int i915_suspend(device_t nbdev) +{ + struct drm_device *dev = device_get_softc(nbdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev || !dev_priv) { + DRM_ERROR("dev: 0x%lx, dev_priv: 0x%lx\n", + (unsigned long) dev, (unsigned long) dev_priv); + DRM_ERROR("DRM not initialized, aborting suspend.\n"); + return -ENODEV; + } + + i915_save_state(dev); + + return (bus_generic_suspend(nbdev)); +} + +static int i915_resume(device_t nbdev) +{ + struct drm_device *dev = device_get_softc(nbdev); + + i915_restore_state(dev); + + return (bus_generic_resume(nbdev)); +} + static void i915_configure(struct drm_device *dev) { - dev->driver.buf_priv_size = 1; /* No dev_priv */ + dev->driver.buf_priv_size = sizeof(drm_i915_private_t); dev->driver.load = i915_driver_load; + dev->driver.unload = i915_driver_unload; + dev->driver.firstopen = i915_driver_firstopen; dev->driver.preclose = i915_driver_preclose; dev->driver.lastclose = i915_driver_lastclose; dev->driver.device_is_agp = i915_driver_device_is_agp; @@ -94,6 +122,8 @@ static device_method_t i915_methods[] = { /* Device interface */ DEVMETHOD(device_probe, i915_probe), DEVMETHOD(device_attach, i915_attach), + DEVMETHOD(device_suspend, i915_suspend), + DEVMETHOD(device_resume, i915_resume), DEVMETHOD(device_detach, drm_detach), { 0, 0 } diff --git a/bsd-core/i915_suspend.c b/bsd-core/i915_suspend.c new file mode 120000 index 00000000..b55754c5 --- /dev/null +++ b/bsd-core/i915_suspend.c @@ -0,0 +1 @@ +../shared-core/i915_suspend.c \ No newline at end of file diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 7a477a10..b9f078dd 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -20,7 +20,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o i915_compat.o i915_execbuf.o + i915_buffer.o i915_compat.o i915_execbuf.o i915_suspend.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ nouveau_sgdma.o nouveau_dma.o nouveau_bo.o nouveau_fence.o \ diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 91c2da23..c5f806b1 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -63,211 +63,9 @@ static struct drm_bo_driver i915_bo_driver = { }; #endif -enum pipe { - PIPE_A = 0, - PIPE_B, -}; - -static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (pipe == PIPE_A) - return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE); - else - return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE); -} - -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); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (pipe == PIPE_A) - array = dev_priv->save_palette_a; - else - array = dev_priv->save_palette_b; - - for(i = 0; i < 256; i++) - array[i] = I915_READ(reg + (i << 2)); -} - -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); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (pipe == PIPE_A) - array = dev_priv->save_palette_a; - else - array = dev_priv->save_palette_b; - - for(i = 0; i < 256; i++) - I915_WRITE(reg + (i << 2), array[i]); -} - -static u8 i915_read_indexed(u16 index_port, u16 data_port, u8 reg) -{ - outb(reg, index_port); - return inb(data_port); -} - -static u8 i915_read_ar(u16 st01, u8 reg, u16 palette_enable) -{ - inb(st01); - outb(palette_enable | reg, VGA_AR_INDEX); - return inb(VGA_AR_DATA_READ); -} - -static void i915_write_ar(u8 st01, u8 reg, u8 val, u16 palette_enable) -{ - inb(st01); - outb(palette_enable | reg, VGA_AR_INDEX); - outb(val, VGA_AR_DATA_WRITE); -} - -static void i915_write_indexed(u16 index_port, u16 data_port, u8 reg, u8 val) -{ - outb(reg, index_port); - outb(val, data_port); -} - -static void i915_save_vga(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - u16 cr_index, cr_data, st01; - - /* VGA color palette registers */ - dev_priv->saveDACMASK = inb(VGA_DACMASK); - /* DACCRX automatically increments during read */ - outb(0, VGA_DACRX); - /* Read 3 bytes of color data from each index */ - for (i = 0; i < 256 * 3; i++) - dev_priv->saveDACDATA[i] = inb(VGA_DACDATA); - - /* MSR bits */ - dev_priv->saveMSR = inb(VGA_MSR_READ); - if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { - cr_index = VGA_CR_INDEX_CGA; - cr_data = VGA_CR_DATA_CGA; - st01 = VGA_ST01_CGA; - } else { - cr_index = VGA_CR_INDEX_MDA; - cr_data = VGA_CR_DATA_MDA; - st01 = VGA_ST01_MDA; - } - - /* CRT controller regs */ - i915_write_indexed(cr_index, cr_data, 0x11, - i915_read_indexed(cr_index, cr_data, 0x11) & - (~0x80)); - for (i = 0; i <= 0x24; i++) - dev_priv->saveCR[i] = - i915_read_indexed(cr_index, cr_data, i); - /* Make sure we don't turn off CR group 0 writes */ - dev_priv->saveCR[0x11] &= ~0x80; - - /* Attribute controller registers */ - inb(st01); - dev_priv->saveAR_INDEX = inb(VGA_AR_INDEX); - for (i = 0; i <= 0x14; i++) - dev_priv->saveAR[i] = i915_read_ar(st01, i, 0); - inb(st01); - outb(dev_priv->saveAR_INDEX, VGA_AR_INDEX); - inb(st01); - - /* Graphics controller registers */ - for (i = 0; i < 9; i++) - dev_priv->saveGR[i] = - i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, i); - - dev_priv->saveGR[0x10] = - i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10); - dev_priv->saveGR[0x11] = - i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11); - dev_priv->saveGR[0x18] = - i915_read_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18); - - /* Sequencer registers */ - for (i = 0; i < 8; i++) - dev_priv->saveSR[i] = - i915_read_indexed(VGA_SR_INDEX, VGA_SR_DATA, i); -} - -static void i915_restore_vga(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - u16 cr_index, cr_data, st01; - - /* MSR bits */ - outb(dev_priv->saveMSR, VGA_MSR_WRITE); - if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { - cr_index = VGA_CR_INDEX_CGA; - cr_data = VGA_CR_DATA_CGA; - st01 = VGA_ST01_CGA; - } else { - cr_index = VGA_CR_INDEX_MDA; - cr_data = VGA_CR_DATA_MDA; - st01 = VGA_ST01_MDA; - } - - /* Sequencer registers, don't write SR07 */ - for (i = 0; i < 7; i++) - i915_write_indexed(VGA_SR_INDEX, VGA_SR_DATA, i, - dev_priv->saveSR[i]); - - /* CRT controller regs */ - /* Enable CR group 0 writes */ - i915_write_indexed(cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); - for (i = 0; i <= 0x24; i++) - i915_write_indexed(cr_index, cr_data, i, dev_priv->saveCR[i]); - - /* Graphics controller regs */ - for (i = 0; i < 9; i++) - i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, i, - dev_priv->saveGR[i]); - - i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x10, - dev_priv->saveGR[0x10]); - i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x11, - dev_priv->saveGR[0x11]); - i915_write_indexed(VGA_GR_INDEX, VGA_GR_DATA, 0x18, - dev_priv->saveGR[0x18]); - - /* Attribute controller registers */ - inb(st01); /* switch back to index mode */ - for (i = 0; i <= 0x14; i++) - i915_write_ar(st01, i, dev_priv->saveAR[i], 0); - inb(st01); /* switch back to index mode */ - outb(dev_priv->saveAR_INDEX | 0x20, VGA_AR_INDEX); - inb(st01); - - /* VGA color palette registers */ - outb(dev_priv->saveDACMASK, VGA_DACMASK); - /* DACCRX automatically increments during read */ - outb(0, VGA_DACWX); - /* Read 3 bytes of color data from each index */ - for (i = 0; i < 256 * 3; i++) - outb(dev_priv->saveDACDATA[i], VGA_DACDATA); - -} - static int i915_suspend(struct drm_device *dev, pm_message_t state) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; if (!dev || !dev_priv) { printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv); @@ -279,122 +77,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) return 0; pci_save_state(dev->pdev); - pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); - - /* Display arbitration control */ - dev_priv->saveDSPARB = I915_READ(DSPARB); - - /* Pipe & plane A info */ - dev_priv->savePIPEACONF = I915_READ(PIPEACONF); - dev_priv->savePIPEASRC = I915_READ(PIPEASRC); - dev_priv->saveFPA0 = I915_READ(FPA0); - dev_priv->saveFPA1 = I915_READ(FPA1); - dev_priv->saveDPLL_A = I915_READ(DPLL_A); - if (IS_I965G(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->saveBCLRPAT_A = I915_READ(BCLRPAT_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->saveDSPABASE = I915_READ(DSPABASE); - if (IS_I965G(dev)) { - dev_priv->saveDSPASURF = I915_READ(DSPASURF); - dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); - } - i915_save_palette(dev, PIPE_A); - dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); - - /* Pipe & plane B info */ - dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); - dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); - dev_priv->saveFPB0 = I915_READ(FPB0); - dev_priv->saveFPB1 = I915_READ(FPB1); - dev_priv->saveDPLL_B = I915_READ(DPLL_B); - if (IS_I965G(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->saveBCLRPAT_A = I915_READ(BCLRPAT_A); - - 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->saveDSPBBASE = I915_READ(DSPBBASE); - if (IS_I965GM(dev) || IS_IGD_GM(dev)) { - dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); - dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); - } - i915_save_palette(dev, PIPE_B); - dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); - /* CRT state */ - dev_priv->saveADPA = I915_READ(ADPA); - - /* LVDS state */ - dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); - if (IS_I965G(dev)) - dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); - if (IS_MOBILE(dev) && !IS_I830(dev)) - dev_priv->saveLVDS = I915_READ(LVDS); - if (!IS_I830(dev) && !IS_845G(dev)) - dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); - dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); - dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); - - /* FIXME: save TV & SDVO state */ - - /* FBC state */ - dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); - dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); - dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); - dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); - - /* Interrupt state */ - dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); - dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); - dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); - - /* VGA state */ - dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); - dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); - dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); - dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); - - /* Clock gating state */ - dev_priv->saveD_STATE = I915_READ(D_STATE); - dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); - - /* Cache mode state */ - dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); - - /* Memory Arbitration state */ - dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); - - /* Scratch space */ - for (i = 0; i < 16; i++) { - dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); - dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); - } - for (i = 0; i < 3; i++) - dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); - - i915_save_vga(dev); + i915_save_state(dev); if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ @@ -408,153 +92,13 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) static int i915_resume(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int i; pci_set_power_state(dev->pdev, PCI_D0); pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) return -1; - pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); - - I915_WRITE(DSPARB, dev_priv->saveDSPARB); - - /* Pipe & plane A info */ - /* Prime the clock */ - if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { - I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & - ~DPLL_VCO_ENABLE); - udelay(150); - } - I915_WRITE(FPA0, dev_priv->saveFPA0); - I915_WRITE(FPA1, dev_priv->saveFPA1); - /* Actually enable it */ - I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); - udelay(150); - if (IS_I965G(dev)) - I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_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(BCLRPAT_A, dev_priv->saveBCLRPAT_A); - - /* Restore plane info */ - I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); - I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); - I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); - I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); - if (IS_I965G(dev)) { - I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); - I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); - } - - I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); - - i915_restore_palette(dev, PIPE_A); - /* Enable the plane */ - I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); - I915_WRITE(DSPABASE, I915_READ(DSPABASE)); - - /* Pipe & plane B info */ - if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { - I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & - ~DPLL_VCO_ENABLE); - udelay(150); - } - I915_WRITE(FPB0, dev_priv->saveFPB0); - I915_WRITE(FPB1, dev_priv->saveFPB1); - /* Actually enable it */ - I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); - udelay(150); - if (IS_I965G(dev)) - I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_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(BCLRPAT_B, dev_priv->saveBCLRPAT_B); - - /* Restore plane info */ - I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); - I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); - I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); - I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); - if (IS_I965G(dev)) { - I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); - I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); - } - - I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); - - i915_restore_palette(dev, PIPE_B); - /* Enable the plane */ - I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); - I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); - - /* CRT state */ - I915_WRITE(ADPA, dev_priv->saveADPA); - - /* LVDS state */ - if (IS_I965G(dev)) - I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); - if (IS_MOBILE(dev) && !IS_I830(dev)) - I915_WRITE(LVDS, dev_priv->saveLVDS); - if (!IS_I830(dev) && !IS_845G(dev)) - I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); - - I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); - I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); - I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); - I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); - I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); - - /* FIXME: restore TV & SDVO state */ - - /* FBC info */ - I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); - I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); - I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); - I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); - - /* VGA state */ - I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); - I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); - I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); - I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); - udelay(150); - - /* Clock gating state */ - I915_WRITE (D_STATE, dev_priv->saveD_STATE); - I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); - - /* Cache mode state */ - I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); - - /* Memory arbitration state */ - I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); - - for (i = 0; i < 16; i++) { - I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); - I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); - } - for (i = 0; i < 3; i++) - I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); - - i915_restore_vga(dev); + i915_restore_state(dev); return 0; } diff --git a/linux-core/i915_suspend.c b/linux-core/i915_suspend.c new file mode 120000 index 00000000..b55754c5 --- /dev/null +++ b/linux-core/i915_suspend.c @@ -0,0 +1 @@ +../shared-core/i915_suspend.c \ No newline at end of file diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 60b405d4..3f4fd1b2 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1008,7 +1008,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, int i915_driver_load(struct drm_device *dev, unsigned long flags) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv; unsigned long base, size; int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 6421f689..427c49fe 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -307,6 +307,11 @@ 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_suspend.c */ +extern int i915_save_state(struct drm_device *dev); +extern int i915_restore_state(struct drm_device *dev); + #ifdef I915_HAVE_FENCE /* i915_fence.c */ extern void i915_fence_handler(struct drm_device *dev); @@ -343,6 +348,12 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev); #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) #define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, (reg), (val)) +#define I915_READ8(reg) DRM_READ8(dev_priv->mmio_map, (reg)) +#define I915_WRITE8(reg,val) DRM_WRITE8(dev_priv->mmio_map, (reg), (val)) + +#if defined(__FreeBSD__) +typedef boolean_t bool; +#endif #define I915_VERBOSE 0 diff --git a/shared-core/i915_suspend.c b/shared-core/i915_suspend.c new file mode 100644 index 00000000..27c82b48 --- /dev/null +++ b/shared-core/i915_suspend.c @@ -0,0 +1,525 @@ +/* i915_suspend.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*- + */ +/* + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + +static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (pipe == PIPE_A) + return (I915_READ(DPLL_A) & DPLL_VCO_ENABLE); + else + return (I915_READ(DPLL_B) & DPLL_VCO_ENABLE); +} + +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); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + array[i] = I915_READ(reg + (i << 2)); +} + +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); + u32 *array; + int i; + + if (!i915_pipe_enabled(dev, pipe)) + return; + + if (pipe == PIPE_A) + array = dev_priv->save_palette_a; + else + array = dev_priv->save_palette_b; + + for(i = 0; i < 256; i++) + I915_WRITE(reg + (i << 2), array[i]); +} + +static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE8(index_port, reg); + return I915_READ8(data_port); +} + +static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_READ8(st01); + I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); + return I915_READ8(VGA_AR_DATA_READ); +} + +static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_READ8(st01); + I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); + I915_WRITE8(VGA_AR_DATA_WRITE, val); +} + +static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE8(index_port, reg); + I915_WRITE8(data_port, val); +} + +static void i915_save_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* VGA color palette registers */ + dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK); + /* DACCRX automatically increments during read */ + I915_WRITE8(VGA_DACRX, 0); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA); + + /* MSR bits */ + dev_priv->saveMSR = I915_READ8(VGA_MSR_READ); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* CRT controller regs */ + i915_write_indexed(dev, cr_index, cr_data, 0x11, + i915_read_indexed(dev, cr_index, cr_data, 0x11) & + (~0x80)); + for (i = 0; i < 0x24; i++) + dev_priv->saveCR[i] = + i915_read_indexed(dev, cr_index, cr_data, i); + /* Make sure we don't turn off CR group 0 writes */ + dev_priv->saveCR[0x11] &= ~0x80; + + /* Attribute controller registers */ + I915_READ8(st01); + dev_priv->saveAR_INDEX = I915_READ8(VGA_AR_INDEX); + for (i = 0; i <= 0x14; i++) + dev_priv->saveAR[i] = i915_read_ar(dev, st01, i, 0); + I915_READ8(st01); + I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX); + I915_READ8(st01); + + /* Graphics controller registers */ + for (i = 0; i < 9; i++) + dev_priv->saveGR[i] = + i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i); + + dev_priv->saveGR[0x10] = + i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10); + dev_priv->saveGR[0x11] = + i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11); + dev_priv->saveGR[0x18] = + i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18); + + /* Sequencer registers */ + for (i = 0; i < 8; i++) + dev_priv->saveSR[i] = + i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i); +} + +static void i915_restore_vga(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + u16 cr_index, cr_data, st01; + + /* MSR bits */ + I915_WRITE8(VGA_MSR_WRITE, dev_priv->saveMSR); + if (dev_priv->saveMSR & VGA_MSR_CGA_MODE) { + cr_index = VGA_CR_INDEX_CGA; + cr_data = VGA_CR_DATA_CGA; + st01 = VGA_ST01_CGA; + } else { + cr_index = VGA_CR_INDEX_MDA; + cr_data = VGA_CR_DATA_MDA; + st01 = VGA_ST01_MDA; + } + + /* Sequencer registers, don't write SR07 */ + for (i = 0; i < 7; i++) + i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i, + dev_priv->saveSR[i]); + + /* CRT controller regs */ + /* Enable CR group 0 writes */ + i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->saveCR[0x11]); + for (i = 0; i <= 0x24; i++) + i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->saveCR[i]); + + /* Graphics controller regs */ + for (i = 0; i < 9; i++) + i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i, + dev_priv->saveGR[i]); + + i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10, + dev_priv->saveGR[0x10]); + i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11, + dev_priv->saveGR[0x11]); + i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18, + dev_priv->saveGR[0x18]); + + /* Attribute controller registers */ + I915_READ8(st01); /* switch back to index mode */ + for (i = 0; i <= 0x14; i++) + i915_write_ar(dev, st01, i, dev_priv->saveAR[i], 0); + I915_READ8(st01); /* switch back to index mode */ + I915_WRITE8(VGA_AR_INDEX, dev_priv->saveAR_INDEX | 0x20); + I915_READ8(st01); + + /* VGA color palette registers */ + I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); + /* DACCRX automatically increments during read */ + I915_WRITE8(VGA_DACWX, 0); + /* Read 3 bytes of color data from each index */ + for (i = 0; i < 256 * 3; i++) + I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]); + +} + +int i915_save_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + +#if defined(__FreeBSD__) + dev_priv->saveLBB = (u8) pci_read_config(dev->device, LBB, 1); +#else + pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); +#endif + + /* Display arbitration control */ + dev_priv->saveDSPARB = I915_READ(DSPARB); + + /* Pipe & plane A info */ + dev_priv->savePIPEACONF = I915_READ(PIPEACONF); + dev_priv->savePIPEASRC = I915_READ(PIPEASRC); + dev_priv->saveFPA0 = I915_READ(FPA0); + dev_priv->saveFPA1 = I915_READ(FPA1); + dev_priv->saveDPLL_A = I915_READ(DPLL_A); + if (IS_I965G(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->saveBCLRPAT_A = I915_READ(BCLRPAT_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->saveDSPABASE = I915_READ(DSPABASE); + if (IS_I965G(dev)) { + dev_priv->saveDSPASURF = I915_READ(DSPASURF); + dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); + } + i915_save_palette(dev, PIPE_A); + dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); + + /* Pipe & plane B info */ + dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); + dev_priv->savePIPEBSRC = I915_READ(PIPEBSRC); + dev_priv->saveFPB0 = I915_READ(FPB0); + dev_priv->saveFPB1 = I915_READ(FPB1); + dev_priv->saveDPLL_B = I915_READ(DPLL_B); + if (IS_I965G(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->saveBCLRPAT_A = I915_READ(BCLRPAT_A); + + 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->saveDSPBBASE = I915_READ(DSPBBASE); + if (IS_I965GM(dev) || IS_IGD_GM(dev)) { + dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); + dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); + } + i915_save_palette(dev, PIPE_B); + dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); + + /* CRT state */ + dev_priv->saveADPA = I915_READ(ADPA); + + /* LVDS state */ + dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); + dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); + dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); + if (IS_I965G(dev)) + dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + dev_priv->saveLVDS = I915_READ(LVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); + dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); + dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); + dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + + /* FIXME: save TV & SDVO state */ + + /* FBC state */ + dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); + dev_priv->saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); + dev_priv->saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); + dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); + + /* Interrupt state */ + dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); + dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); + dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + + /* VGA state */ + dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); + dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); + dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); + + /* Clock gating state */ + dev_priv->saveD_STATE = I915_READ(D_STATE); + dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + + /* Cache mode state */ + dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); + + /* Memory Arbitration state */ + dev_priv->saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); + + /* Scratch space */ + for (i = 0; i < 16; i++) { + dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); + } + for (i = 0; i < 3; i++) + dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); + + i915_save_vga(dev); + + return 0; +} + +int i915_restore_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + +#if defined(__FreeBSD__) + pci_write_config(dev->device, LBB, dev_priv->saveLBB, 1); +#else + pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); +#endif + + I915_WRITE(DSPARB, dev_priv->saveDSPARB); + + /* Pipe & plane A info */ + /* Prime the clock */ + if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A & + ~DPLL_VCO_ENABLE); + DRM_UDELAY(150); + } + I915_WRITE(FPA0, dev_priv->saveFPA0); + I915_WRITE(FPA1, dev_priv->saveFPA1); + /* Actually enable it */ + I915_WRITE(DPLL_A, dev_priv->saveDPLL_A); + DRM_UDELAY(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD); + DRM_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(BCLRPAT_A, dev_priv->saveBCLRPAT_A); + + /* Restore plane info */ + I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); + I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); + I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); + I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); + I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF); + } + + I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF); + + i915_restore_palette(dev, PIPE_A); + /* Enable the plane */ + I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); + I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + + /* Pipe & plane B info */ + if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B & + ~DPLL_VCO_ENABLE); + DRM_UDELAY(150); + } + I915_WRITE(FPB0, dev_priv->saveFPB0); + I915_WRITE(FPB1, dev_priv->saveFPB1); + /* Actually enable it */ + I915_WRITE(DPLL_B, dev_priv->saveDPLL_B); + DRM_UDELAY(150); + if (IS_I965G(dev)) + I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD); + DRM_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(BCLRPAT_B, dev_priv->saveBCLRPAT_B); + + /* Restore plane info */ + I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); + I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); + I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); + I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); + if (IS_I965G(dev)) { + I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); + I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF); + } + + I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF); + + i915_restore_palette(dev, PIPE_B); + /* Enable the plane */ + I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); + I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + + /* CRT state */ + I915_WRITE(ADPA, dev_priv->saveADPA); + + /* LVDS state */ + if (IS_I965G(dev)) + I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2); + if (IS_MOBILE(dev) && !IS_I830(dev)) + I915_WRITE(LVDS, dev_priv->saveLVDS); + if (!IS_I830(dev) && !IS_845G(dev)) + I915_WRITE(PFIT_CONTROL, dev_priv->savePFIT_CONTROL); + + I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); + I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); + I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); + I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); + I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); + + /* FIXME: restore TV & SDVO state */ + + /* FBC info */ + I915_WRITE(FBC_CFB_BASE, dev_priv->saveFBC_CFB_BASE); + I915_WRITE(FBC_LL_BASE, dev_priv->saveFBC_LL_BASE); + I915_WRITE(FBC_CONTROL2, dev_priv->saveFBC_CONTROL2); + I915_WRITE(FBC_CONTROL, dev_priv->saveFBC_CONTROL); + + /* VGA state */ + I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); + I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); + I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); + I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + DRM_UDELAY(150); + + /* Clock gating state */ + I915_WRITE (D_STATE, dev_priv->saveD_STATE); + I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + + /* Cache mode state */ + I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); + + /* Memory arbitration state */ + I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); + + for (i = 0; i < 16; i++) { + I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); + I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); + } + for (i = 0; i < 3; i++) + I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); + + i915_restore_vga(dev); + + return 0; +} + -- cgit v1.2.3 From 63eb58040deff42e8272f1a580f7fd947af1b488 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Sun, 8 Jun 2008 23:46:14 -0400 Subject: Fix typo in i915_suspend Reported by vehemens --- shared-core/i915_suspend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_suspend.c b/shared-core/i915_suspend.c index 27c82b48..d93bf6b3 100644 --- a/shared-core/i915_suspend.c +++ b/shared-core/i915_suspend.c @@ -149,7 +149,7 @@ static void i915_save_vga(struct drm_device *dev) i915_write_indexed(dev, cr_index, cr_data, 0x11, i915_read_indexed(dev, cr_index, cr_data, 0x11) & (~0x80)); - for (i = 0; i < 0x24; i++) + for (i = 0; i <= 0x24; i++) dev_priv->saveCR[i] = i915_read_indexed(dev, cr_index, cr_data, i); /* Make sure we don't turn off CR group 0 writes */ -- cgit v1.2.3 From f6982b54c96bc871df94d01abad72a501e87aa65 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 9 Jun 2008 16:28:35 -0400 Subject: RADEON: switch IGP gart to use radeon_write_agp_base() --- shared-core/radeon_cp.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 75b1dc55..696f12be 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -126,6 +126,9 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) { R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi); + } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) { + RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); + RADEON_WRITE(RS480_AGP_BASE_2, 0); } else { RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200) @@ -741,14 +744,7 @@ static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on) IGP_WRITE_MCIND(RS480_AGP_MODE_CNTL, ((1 << RS480_REQ_TYPE_SNOOP_SHIFT) | RS480_REQ_TYPE_SNOOP_DIS)); - if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS690) { - IGP_WRITE_MCIND(RS690_MC_AGP_BASE, - (unsigned int)dev_priv->gart_vm_start); - IGP_WRITE_MCIND(RS690_MC_AGP_BASE_2, 0); - } else { - RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start); - RADEON_WRITE(RS480_AGP_BASE_2, 0); - } + radeon_write_agp_base(dev_priv, dev_priv->gart_vm_start); dev_priv->gart_size = 32*1024*1024; temp = (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & -- cgit v1.2.3 From 4b8aecbde8e62af5370d5401d49a8ab8d089fe8e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 9 Jun 2008 16:58:06 -0400 Subject: RADEON: Add untested support for RS400 chips GART setup appears to work the same as RS480 chips. Also RC4xx chips are actually RS400 based, not RS480 based. --- shared-core/drm_pciids.txt | 8 +++++--- shared-core/radeon_cp.c | 6 ++++-- shared-core/radeon_drv.h | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 86408a4b..f48258a3 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -99,7 +99,7 @@ 0x1002 0x5653 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 M26" 0x1002 0x5834 CHIP_RS300|RADEON_IS_IGP "ATI Radeon RS300 9100 IGP" 0x1002 0x5835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS300 Mobility IGP" -0x1002 0x5954 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI RS480 XPRESS 200G" +0x1002 0x5954 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_IGPGART "ATI RS480 XPRESS 200G" 0x1002 0x5955 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon XPRESS 200M 5955" 0x1002 0x5974 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon RS482 XPRESS 200" 0x1002 0x5975 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon RS485 XPRESS 1100 IGP" @@ -109,8 +109,10 @@ 0x1002 0x5964 CHIP_RV280 "ATI Radeon RV280 9200 SE" 0x1002 0x5965 CHIP_RV280 "ATI FireMV 2200 PCI" 0x1002 0x5969 CHIP_RV100 "ATI ES1000 RN50" -0x1002 0x5a61 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon RC410 XPRESS 200" -0x1002 0x5a62 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon RC410 XPRESS 200M" +0x1002 0x5a41 CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART "ATI Radeon XPRESS 200 5A41 (PCIE)" +0x1002 0x5a42 CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon XPRESS 200M 5A42 (PCIE)" +0x1002 0x5a61 CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART "ATI Radeon RC410 XPRESS 200" +0x1002 0x5a62 CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART "ATI Radeon RC410 XPRESS 200M" 0x1002 0x5b60 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X300 SE" 0x1002 0x5b62 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X600 Pro" 0x1002 0x5b63 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550" diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 696f12be..afe850c1 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -126,9 +126,10 @@ static void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) } else if ((dev_priv->flags & RADEON_FAMILY_MASK) > CHIP_RV515) { R500_WRITE_MCIND(R520_MC_AGP_BASE, agp_base_lo); R500_WRITE_MCIND(R520_MC_AGP_BASE_2, agp_base_hi); - } else if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480) { + } else if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) { RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); - RADEON_WRITE(RS480_AGP_BASE_2, 0); + RADEON_WRITE(RS480_AGP_BASE_2, agp_base_hi); } else { RADEON_WRITE(RADEON_AGP_BASE, agp_base_lo); if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R200) @@ -355,6 +356,7 @@ static void radeon_cp_load_microcode(drm_radeon_private_t * dev_priv) ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV350) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV380) || + ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS400) || ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RS480)) { DRM_INFO("Loading R300 Microcode\n"); for (i = 0; i < 256; i++) { diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 1b59f871..760e0573 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -124,6 +124,7 @@ enum radeon_family { CHIP_RV380, CHIP_R420, CHIP_RV410, + CHIP_RS400, CHIP_RS480, CHIP_RS690, CHIP_RV515, -- cgit v1.2.3 From cdd0cb0ab372ac93adc73945627f4071f86f75c0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 10 Jun 2008 16:27:50 +1000 Subject: ati_pcigart: split out the page insert function --- linux-core/ati_pcigart.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index c2aafd22..fb663a0a 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -39,6 +39,28 @@ #define ATI_PCIE_WRITE 0x4 #define ATI_PCIE_READ 0x8 +static __inline__ void gart_insert_page_into_table(struct drm_ati_pcigart_info *gart_info, dma_addr_t addr, u32 *pci_gart) +{ + u32 page_base; + + page_base = (u32)addr & ATI_PCIGART_PAGE_MASK; + switch(gart_info->gart_reg_if) { + case DRM_ATI_GART_IGP: + page_base |= (upper_32_bits(addr) & 0xff) << 4; + page_base |= 0xc; + break; + case DRM_ATI_GART_PCIE: + page_base >>= 8; + page_base |= (upper_32_bits(addr) & 0xff) << 24; + page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; + break; + default: + case DRM_ATI_GART_PCI: + break; + } + *pci_gart = cpu_to_le32(page_base); +} + static int drm_ati_alloc_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { @@ -155,22 +177,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga entry_addr = entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { - page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; - switch(gart_info->gart_reg_if) { - case DRM_ATI_GART_IGP: - page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; - page_base |= 0xc; - break; - case DRM_ATI_GART_PCIE: - page_base >>= 8; - page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; - page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; - break; - default: - case DRM_ATI_GART_PCI: - break; - } - *pci_gart = cpu_to_le32(page_base); + gart_insert_page_into_table(gart_info, entry_addr, pci_gart); pci_gart++; entry_addr += ATI_PCIGART_PAGE_SIZE; } -- cgit v1.2.3 From 4f3da2f200577fcfbf913985246b3a4d23c6a818 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 12 May 2008 15:58:55 -0700 Subject: xgi: Fix 64-bit kernel / 32-bit user issue. --- linux-core/xgi_drv.h | 2 +- linux-core/xgi_fb.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 9408073e..0d85e559 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -86,7 +86,7 @@ extern int xgi_fb_heap_init(struct xgi_info * info); extern int xgi_alloc(struct xgi_info * info, struct xgi_mem_alloc * alloc, struct drm_file * filp); -extern int xgi_free(struct xgi_info * info, unsigned long index, +extern int xgi_free(struct xgi_info * info, unsigned int index, struct drm_file * filp); extern int xgi_pcie_heap_init(struct xgi_info * info); diff --git a/linux-core/xgi_fb.c b/linux-core/xgi_fb.c index 3f50fe8f..e793bd3f 100644 --- a/linux-core/xgi_fb.c +++ b/linux-core/xgi_fb.c @@ -93,7 +93,7 @@ int xgi_alloc_ioctl(struct drm_device * dev, void * data, } -int xgi_free(struct xgi_info * info, unsigned long index, +int xgi_free(struct xgi_info * info, unsigned int index, struct drm_file * filp) { int err; @@ -111,7 +111,7 @@ int xgi_free_ioctl(struct drm_device * dev, void * data, { struct xgi_info *info = dev->dev_private; - return xgi_free(info, *(unsigned long *) data, filp); + return xgi_free(info, *(unsigned int *) data, filp); } -- cgit v1.2.3 From b535567ee95b8407d7860a4d6350df8e8fbac15a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 10 Jun 2008 22:18:14 -0700 Subject: xgixp: Remove dependency on TTM fences --- linux-core/xgi_cmdlist.c | 2 ++ linux-core/xgi_drv.c | 21 ++++++++++- linux-core/xgi_drv.h | 13 +++++++ linux-core/xgi_fence.c | 92 ++++++++++++++++++++++++++++++++++++++++-------- shared-core/xgi_drm.h | 4 +++ 5 files changed, 117 insertions(+), 15 deletions(-) diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c index 64401ae5..e433c21d 100644 --- a/linux-core/xgi_cmdlist.c +++ b/linux-core/xgi_cmdlist.c @@ -148,7 +148,9 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data, } info->cmdring.last_ptr = xgi_find_pcie_virt(info, pCmdInfo->hw_addr); +#ifdef XGI_HAVE_FENCE drm_fence_flush_old(info->dev, 0, info->next_sequence); +#endif /* XGI_HAVE_FENCE */ return 0; } diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index f0225f89..532408db 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,7 +37,9 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; +#ifdef XGI_HAVE_FENCE extern struct drm_fence_driver xgi_fence_driver; +#endif /* XGI_HAVE_FENCE */ int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); @@ -47,6 +49,8 @@ static struct drm_ioctl_desc xgi_ioctls[] = { DRM_IOCTL_DEF(DRM_XGI_FREE, xgi_free_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_SUBMIT_CMDLIST, xgi_submit_cmdlist, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_STATE_CHANGE, xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER), + DRM_IOCTL_DEF(DRM_XGI_SET_FENCE, xgi_set_fence_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_WAIT_FENCE, xgi_wait_fence_ioctl, DRM_AUTH), }; static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); @@ -58,6 +62,7 @@ static void xgi_driver_lastclose(struct drm_device * dev); static void xgi_reclaim_buffers_locked(struct drm_device * dev, struct drm_file * filp); static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); +static int xgi_kern_isr_postinstall(struct drm_device * dev); static struct drm_driver driver = { @@ -70,7 +75,7 @@ static struct drm_driver driver = { .lastclose = xgi_driver_lastclose, .dma_quiescent = NULL, .irq_preinstall = NULL, - .irq_postinstall = NULL, + .irq_postinstall = xgi_kern_isr_postinstall, .irq_uninstall = NULL, .irq_handler = xgi_kern_isr, .reclaim_buffers = drm_core_reclaim_buffers, @@ -100,7 +105,9 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, +#ifdef XGI_HAVE_FENCE .fence_driver = &xgi_fence_driver, +#endif /* XGI_HAVE_FENCE */ .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -355,7 +362,10 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) DRM_WRITE32(info->mmio_map, 0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS, cpu_to_le32(M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits)); +#ifdef XGI_HAVE_FENCE xgi_fence_handler(dev); +#endif /* XGI_HAVE_FENCE */ + DRM_WAKEUP(&info->fence_queue); return IRQ_HANDLED; } else { return IRQ_NONE; @@ -363,6 +373,15 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) } +int xgi_kern_isr_postinstall(struct drm_device * dev) +{ + struct xgi_info *info = dev->dev_private; + + DRM_INIT_WAITQUEUE(&info->fence_queue); + return 0; +} + + int xgi_driver_load(struct drm_device *dev, unsigned long flags) { struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 0d85e559..2fd73b9e 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -74,6 +74,7 @@ struct xgi_info { struct xgi_cmdring_info cmdring; DRM_SPINTYPE fence_lock; + wait_queue_head_t fence_queue; unsigned complete_sequence; unsigned next_sequence; }; @@ -98,12 +99,24 @@ extern void xgi_disable_mmio(struct xgi_info * info); extern void xgi_enable_ge(struct xgi_info * info); extern void xgi_disable_ge(struct xgi_info * info); +/* TTM-style fences. + */ +#ifdef XGI_HAVE_FENCE extern void xgi_poke_flush(struct drm_device * dev, uint32_t class); extern int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, uint32_t * sequence, uint32_t * native_type); extern void xgi_fence_handler(struct drm_device * dev); extern int xgi_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags); +#endif /* XGI_HAVE_FENCE */ + + +/* Non-TTM-style fences. + */ +extern int xgi_set_fence_ioctl(struct drm_device * dev, void * data, + struct drm_file * filp); +extern int xgi_wait_fence_ioctl(struct drm_device * dev, void * data, + struct drm_file * filp); extern int xgi_alloc_ioctl(struct drm_device * dev, void * data, struct drm_file * filp); diff --git a/linux-core/xgi_fence.c b/linux-core/xgi_fence.c index 63ed29ee..38cf9e4f 100644 --- a/linux-core/xgi_fence.c +++ b/linux-core/xgi_fence.c @@ -30,6 +30,76 @@ #include "xgi_misc.h" #include "xgi_cmdlist.h" +static int xgi_low_level_fence_emit(struct drm_device *dev, u32 *sequence) +{ + struct xgi_info *const info = dev->dev_private; + + if (info == NULL) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + DRM_SPINLOCK(&info->fence_lock); + info->next_sequence++; + if (info->next_sequence > BEGIN_BEGIN_IDENTIFICATION_MASK) { + info->next_sequence = 1; + } + + *sequence = (u32) info->next_sequence; + DRM_SPINUNLOCK(&info->fence_lock); + + + xgi_emit_irq(info); + return 0; +} + +#define GET_BEGIN_ID(i) (le32_to_cpu(DRM_READ32((i)->mmio_map, 0x2820)) \ + & BEGIN_BEGIN_IDENTIFICATION_MASK) + +static int xgi_low_level_fence_wait(struct drm_device *dev, unsigned *sequence) +{ + struct xgi_info *const info = dev->dev_private; + unsigned int cur_fence; + int ret = 0; + + if (info == NULL) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using fences. + */ + DRM_WAIT_ON(ret, info->fence_queue, 3 * DRM_HZ, + ((((cur_fence = GET_BEGIN_ID(info)) + - *sequence) & BEGIN_BEGIN_IDENTIFICATION_MASK) + <= (1 << 18))); + + info->complete_sequence = cur_fence; + *sequence = cur_fence; + + return ret; +} + + +int xgi_set_fence_ioctl(struct drm_device * dev, void * data, + struct drm_file * filp) +{ + (void) filp; + return xgi_low_level_fence_emit(dev, (u32 *) data); +} + + +int xgi_wait_fence_ioctl(struct drm_device * dev, void * data, + struct drm_file * filp) +{ + (void) filp; + return xgi_low_level_fence_wait(dev, (u32 *) data); +} + + +#ifdef XGI_HAVE_FENCE static void xgi_fence_poll(struct drm_device * dev, uint32_t class, uint32_t waiting_types) { @@ -68,25 +138,18 @@ int xgi_fence_emit_sequence(struct drm_device * dev, uint32_t class, uint32_t flags, uint32_t * sequence, uint32_t * native_type) { - struct xgi_info * info = dev->dev_private; + int err; - if ((info == NULL) || (class != 0)) - return -EINVAL; - - - DRM_SPINLOCK(&info->fence_lock); - info->next_sequence++; - if (info->next_sequence > BEGIN_BEGIN_IDENTIFICATION_MASK) { - info->next_sequence = 1; - } - DRM_SPINUNLOCK(&info->fence_lock); + (void) flags; + if (class != 0) + return -EINVAL; - xgi_emit_irq(info); + err = xgi_low_level_fence_emit(dev, sequence); + if (err) + return err; - *sequence = (uint32_t) info->next_sequence; *native_type = DRM_FENCE_TYPE_EXE; - return 0; } @@ -120,3 +183,4 @@ struct drm_fence_driver xgi_fence_driver = { .wait = NULL }; +#endif /* XGI_HAVE_FENCE */ diff --git a/shared-core/xgi_drm.h b/shared-core/xgi_drm.h index ce584420..7d01065e 100644 --- a/shared-core/xgi_drm.h +++ b/shared-core/xgi_drm.h @@ -123,11 +123,15 @@ struct xgi_state_info { #define DRM_XGI_FREE 2 #define DRM_XGI_SUBMIT_CMDLIST 3 #define DRM_XGI_STATE_CHANGE 4 +#define DRM_XGI_SET_FENCE 5 +#define DRM_XGI_WAIT_FENCE 6 #define XGI_IOCTL_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_BOOTSTRAP, struct xgi_bootstrap) #define XGI_IOCTL_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_ALLOC, struct xgi_mem_alloc) #define XGI_IOCTL_FREE DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_FREE, __u32) #define XGI_IOCTL_SUBMIT_CMDLIST DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_SUBMIT_CMDLIST, struct xgi_cmd_info) #define XGI_IOCTL_STATE_CHANGE DRM_IOW(DRM_COMMAND_BASE + DRM_XGI_STATE_CHANGE, struct xgi_state_info) +#define XGI_IOCTL_SET_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_SET_FENCE, u32) +#define XGI_IOCTL_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_XGI_WAIT_FENCE, u32) #endif /* _XGI_DRM_H_ */ -- cgit v1.2.3 From a07c82183abdcde9777a456d45b7ae741ddfd44c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 11 Jun 2008 18:25:47 -0400 Subject: RADEON: use DSTCACHE_CTLSTAT rather than RB2D_DSTCACHE_CTLSTAT According to the hw guys, you should use DSTCACHE_CTLSTAT to flush the 2D dst cache rather than RB2D_DSTCACHE_CTLSTAT. --- shared-core/radeon_cp.c | 6 +++--- shared-core/radeon_drv.h | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index afe850c1..7317d184 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -204,12 +204,12 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv) RADEON_WRITE(R300_RB3D_DSTCACHE_CTLSTAT, tmp); /* 2D */ - tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT); + tmp = RADEON_READ(R300_DSTCACHE_CTLSTAT); tmp |= RADEON_RB3D_DC_FLUSH_ALL; - RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp); + RADEON_WRITE(R300_DSTCACHE_CTLSTAT, tmp); for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT) + if (!(RADEON_READ(R300_DSTCACHE_CTLSTAT) & RADEON_RB3D_DC_BUSY)) { return 0; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 760e0573..20f9b956 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -673,11 +673,12 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 -#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c -# define RADEON_RB2D_DC_FLUSH (3 << 0) -# define RADEON_RB2D_DC_FREE (3 << 2) -# define RADEON_RB2D_DC_FLUSH_ALL 0xf -# define RADEON_RB2D_DC_BUSY (1 << 31) +#define R300_RB2D_DSTCACHE_CTLSTAT 0x342c /* use R300_DSTCACHE_CTLSTAT */ +#define R300_DSTCACHE_CTLSTAT 0x1714 +# define R300_RB2D_DC_FLUSH (3 << 0) +# define R300_RB2D_DC_FREE (3 << 2) +# define R300_RB2D_DC_FLUSH_ALL 0xf +# define R300_RB2D_DC_BUSY (1 << 31) #define RADEON_RB3D_CNTL 0x1c3c # define RADEON_ALPHA_BLEND_ENABLE (1 << 0) # define RADEON_PLANE_MASK_ENABLE (1 << 1) -- cgit v1.2.3 From 5d99e79c3ee027a035d4ef0a920e3fc30bd053c1 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 12 Jun 2008 15:36:48 -0700 Subject: xgi: Bump kernel version This should have been bumped when the fence interface was changed the other day. Better late than never, I suppose. --- linux-core/xgi_drv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/xgi_drv.h b/linux-core/xgi_drv.h index 2fd73b9e..5ad3ddb3 100644 --- a/linux-core/xgi_drv.h +++ b/linux-core/xgi_drv.h @@ -35,11 +35,11 @@ #define DRIVER_NAME "xgi" #define DRIVER_DESC "XGI XP5 / XP10 / XG47" -#define DRIVER_DATE "20071003" +#define DRIVER_DATE "20080612" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 1 -#define DRIVER_PATCHLEVEL 3 +#define DRIVER_MINOR 2 +#define DRIVER_PATCHLEVEL 0 #include "xgi_cmdlist.h" #include "xgi_drm.h" -- cgit v1.2.3 From 1aafbb83d97ccc78b78d5cbd311f1239a3dad11e Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 13 Jun 2008 09:54:05 +0200 Subject: radeon: r345xx fixe hard lockup This patch should fixe hard lockup and convert them in softlockup (ie you can ssh the box but the gpu is busted and we are waiting in loop for it to come back to reason). --- shared-core/r300_cmdbuf.c | 120 ++++++++++++++++++++++++++++++++++++++-------- shared-core/r300_reg.h | 5 +- shared-core/radeon_cp.c | 38 +++++++-------- shared-core/radeon_drv.h | 31 +++++++----- 4 files changed, 138 insertions(+), 56 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index e9f99c8f..addc075d 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -136,6 +136,18 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv, ADVANCE_RING(); } + /* flus cache and wait idle clean after cliprect change */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB3D_DC_FLUSH); + ADVANCE_RING(); + BEGIN_RING(2); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_3D_IDLECLEAN); + ADVANCE_RING(); + /* set flush flag */ + dev_priv->track_flush |= RADEON_FLUSH_EMITED; + return 0; } @@ -166,13 +178,13 @@ void r300_init_reg_flags(struct drm_device *dev) ADD_RANGE(0x21DC, 1); ADD_RANGE(R300_VAP_UNKNOWN_221C, 1); ADD_RANGE(R300_VAP_CLIP_X_0, 4); - ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1); + ADD_RANGE(R300_VAP_PVS_STATE_FLUSH_REG, 1); ADD_RANGE(R300_VAP_UNKNOWN_2288, 1); ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2); ADD_RANGE(R300_VAP_PVS_CNTL_1, 3); ADD_RANGE(R300_GB_ENABLE, 1); ADD_RANGE(R300_GB_MSPOS0, 5); - ADD_RANGE(R300_TX_CNTL, 1); + ADD_RANGE(R300_TX_INVALTAGS, 1); ADD_RANGE(R300_TX_ENABLE, 1); ADD_RANGE(0x4200, 4); ADD_RANGE(0x4214, 1); @@ -389,15 +401,28 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv, if (sz * 16 > cmdbuf->bufsz) return -EINVAL; - BEGIN_RING(5 + sz * 4); - /* Wait for VAP to come to senses.. */ - /* there is no need to emit it multiple times, (only once before VAP is programmed, - but this optimization is for later */ - OUT_RING_REG(R300_VAP_PVS_WAITIDLE, 0); + /* VAP is very sensitive so we purge cache before we program it + * and we also flush its state before & after */ + BEGIN_RING(6); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB3D_DC_FLUSH); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_3D_IDLECLEAN); + OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0)); + OUT_RING(0); + ADVANCE_RING(); + /* set flush flag */ + dev_priv->track_flush |= RADEON_FLUSH_EMITED; + + BEGIN_RING(3 + sz * 4); OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr); OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1)); OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4); + ADVANCE_RING(); + BEGIN_RING(2); + OUT_RING(CP_PACKET0(R300_VAP_PVS_STATE_FLUSH_REG, 0)); + OUT_RING(0); ADVANCE_RING(); cmdbuf->buf += sz * 16; @@ -425,6 +450,15 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv, OUT_RING_TABLE((int *)cmdbuf->buf, 8); ADVANCE_RING(); + BEGIN_RING(4); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB3D_DC_FLUSH); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_3D_IDLECLEAN); + ADVANCE_RING(); + /* set flush flag */ + dev_priv->track_flush |= RADEON_FLUSH_EMITED; + cmdbuf->buf += 8 * 4; cmdbuf->bufsz -= 8 * 4; @@ -614,13 +648,23 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, case RADEON_CNTL_BITBLT_MULTI: return r300_emit_bitblt_multi(dev_priv, cmdbuf); - case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ + case RADEON_CP_INDX_BUFFER: + /* whenever we send vertex we clear flush & purge */ + dev_priv->track_flush ^= (RADEON_FLUSH_EMITED | + RADEON_PURGE_EMITED); + /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ return r300_emit_indx_buffer(dev_priv, cmdbuf); - case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ - case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ - case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ + case RADEON_CP_3D_DRAW_IMMD_2: + /* triggers drawing using in-packet vertex data */ + case RADEON_CP_3D_DRAW_VBUF_2: + /* triggers drawing of vertex buffers setup elsewhere */ + case RADEON_CP_3D_DRAW_INDX_2: + /* triggers drawing using indices to vertex buffer */ case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: + /* whenever we send vertex we clear flush & purge */ + dev_priv->track_flush ^= (RADEON_FLUSH_EMITED | + RADEON_PURGE_EMITED); /* these packets are safe */ break; default: @@ -715,16 +759,47 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) { RING_LOCALS; + + if ((dev_priv->track_flush & RADEON_PURGE_EMITED)) { + /* purge already emited without vertex in btw don't purge + * again or lockup will likely happen */ + return; + } - BEGIN_RING(6); - OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); - OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A); + /* flush & purge zbuffer */ + BEGIN_RING(2); OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); - OUT_RING(R300_ZB_ZCACHE_CTLSTAT_ZC_FLUSH_FLUSH_AND_FREE| - R300_ZB_ZCACHE_CTLSTAT_ZC_FREE_FREE); - OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0)); - OUT_RING(0x0); + OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); + ADVANCE_RING(); + /* flush & purge 3d */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + ADVANCE_RING(); + /* flush & purge texture */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(R300_TX_INVALTAGS, 0)); + OUT_RING(0); + ADVANCE_RING(); + /* FIXME: is this one really needed ? */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(R300_RB3D_AARESOLVE_CTL, 0)); + OUT_RING(0); ADVANCE_RING(); + BEGIN_RING(2); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_3D_IDLECLEAN); + ADVANCE_RING(); + /* flush & purge 2d through E2 as RB2D will trigger lockup */ + BEGIN_RING(4); + OUT_RING(CP_PACKET0(R300_DSTCACHE_CTLSTAT, 0)); + OUT_RING(R300_RB2D_DC_FLUSH | R300_RB2D_DC_FREE); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_2D_IDLECLEAN | + RADEON_WAIT_HOST_IDLECLEAN); + ADVANCE_RING(); + /* set flush & purge flags */ + dev_priv->track_flush |= RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED; } /** @@ -902,12 +977,15 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, struct drm_buf *buf = NULL; int emit_dispatch_age = 0; int ret = 0; + RING_LOCALS; DRM_DEBUG("\n"); - /* See the comment above r300_emit_begin3d for why this call must be here, - * and what the cleanup gotos are for. */ - r300_pacify(dev_priv); + /* start by a wait, should be necessary */ + BEGIN_RING(2); + OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); + OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_2D_IDLE); + ADVANCE_RING(); if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) { ret = r300_emit_cliprects(dev_priv, cmdbuf, 0); diff --git a/shared-core/r300_reg.h b/shared-core/r300_reg.h index 1920ab07..d35dd39d 100644 --- a/shared-core/r300_reg.h +++ b/shared-core/r300_reg.h @@ -320,7 +320,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * Therefore, I suspect writing zero to 0x2284 synchronizes the engine and * avoids bugs caused by still running shaders reading bad data from memory. */ -#define R300_VAP_PVS_WAITIDLE 0x2284 /* GUESS */ +#define R300_VAP_PVS_STATE_FLUSH_REG 0x2284 /* Absolutely no clue what this register is about. */ #define R300_VAP_UNKNOWN_2288 0x2288 @@ -516,7 +516,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* gap */ /* Zero to flush caches. */ -#define R300_TX_CNTL 0x4100 +#define R300_TX_INVALTAGS 0x4100 #define R300_TX_FLUSH 0x0 /* The upper enable bits are guessed, based on fglrx reported limits. */ @@ -1365,6 +1365,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */ #define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */ +#define R300_RB3D_AARESOLVE_CTL 0x4E88 /* gap */ /* Guess by Vladimir. diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 7317d184..ec914df1 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -39,6 +39,7 @@ #define RADEON_FIFO_DEBUG 0 static int radeon_do_cleanup_cp(struct drm_device * dev); +static void radeon_do_cp_start(drm_radeon_private_t * dev_priv); static u32 R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr) { @@ -198,23 +199,8 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv) DRM_UDELAY(1); } } else { - /* 3D */ - tmp = RADEON_READ(R300_RB3D_DSTCACHE_CTLSTAT); - tmp |= RADEON_RB3D_DC_FLUSH_ALL; - RADEON_WRITE(R300_RB3D_DSTCACHE_CTLSTAT, tmp); - - /* 2D */ - tmp = RADEON_READ(R300_DSTCACHE_CTLSTAT); - tmp |= RADEON_RB3D_DC_FLUSH_ALL; - RADEON_WRITE(R300_DSTCACHE_CTLSTAT, tmp); - - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(RADEON_READ(R300_DSTCACHE_CTLSTAT) - & RADEON_RB3D_DC_BUSY)) { - return 0; - } - DRM_UDELAY(1); - } + /* don't flush or purge cache here or lockup */ + return 0; } #if RADEON_FIFO_DEBUG @@ -237,6 +223,9 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries) return 0; DRM_UDELAY(1); } + DRM_INFO("wait for fifo failed status : 0x%08X 0x%08X\n", + RADEON_READ(RADEON_RBBM_STATUS), + RADEON_READ(R300_VAP_CNTL_STATUS)); #if RADEON_FIFO_DEBUG DRM_ERROR("failed!\n"); @@ -263,6 +252,9 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv) } DRM_UDELAY(1); } + DRM_INFO("wait idle failed status : 0x%08X 0x%08X\n", + RADEON_READ(RADEON_RBBM_STATUS), + RADEON_READ(R300_VAP_CNTL_STATUS)); #if RADEON_FIFO_DEBUG DRM_ERROR("failed!\n"); @@ -445,14 +437,20 @@ static void radeon_do_cp_start(drm_radeon_private_t * dev_priv) dev_priv->cp_running = 1; - BEGIN_RING(6); - + BEGIN_RING(8); + /* isync can only be written through cp on r5xx write it here */ + OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 0)); + OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_CPSCRATCH_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI); RADEON_PURGE_CACHE(); RADEON_PURGE_ZCACHE(); RADEON_WAIT_UNTIL_IDLE(); - ADVANCE_RING(); COMMIT_RING(); + + dev_priv->track_flush |= RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED; } /* Reset the Command Processor. This will not flush any pending diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 20f9b956..71669c22 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -222,6 +222,9 @@ struct radeon_virt_surface { struct drm_file *file_priv; }; +#define RADEON_FLUSH_EMITED (1 < 0) +#define RADEON_PURGE_EMITED (1 < 1) + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; @@ -317,6 +320,7 @@ typedef struct drm_radeon_private { unsigned long fb_aper_offset; int num_gb_pipes; + int track_flush; } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -704,7 +708,6 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, #define R300_ZB_ZCACHE_CTLSTAT 0x4f18 # define R300_ZC_FLUSH (1 << 0) # define R300_ZC_FREE (1 << 1) -# define R300_ZC_FLUSH_ALL 0x3 # define R300_ZC_BUSY (1 << 31) #define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c # define RADEON_RB3D_DC_FLUSH (3 << 0) @@ -712,6 +715,8 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev, # define RADEON_RB3D_DC_FLUSH_ALL 0xf # define RADEON_RB3D_DC_BUSY (1 << 31) #define R300_RB3D_DSTCACHE_CTLSTAT 0x4e4c +# define R300_RB3D_DC_FLUSH (2 << 0) +# define R300_RB3D_DC_FREE (2 << 2) # define R300_RB3D_DC_FINISH (1 << 4) #define RADEON_RB3D_ZSTENCILCNTL 0x1c2c # define RADEON_Z_TEST_MASK (7 << 4) @@ -1281,21 +1286,21 @@ do { \ #define RADEON_FLUSH_CACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH ); \ + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(R300_RB3D_DC_FLUSH); \ } \ } while (0) #define RADEON_PURGE_CACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_DC_FLUSH | RADEON_RB3D_DC_FREE); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE ); \ } \ } while (0) @@ -1311,11 +1316,11 @@ do { \ #define RADEON_PURGE_ZCACHE() do { \ if ((dev_priv->flags & RADEON_FAMILY_MASK) <= CHIP_RV280) { \ - OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE); \ } else { \ - OUT_RING( CP_PACKET0( R300_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \ - OUT_RING( R300_ZC_FLUSH_ALL ); \ + OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); \ } \ } while (0) -- cgit v1.2.3 From 00b406390649175bb432da5693bfbd3360ad21b3 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 13 Jun 2008 10:02:41 +0200 Subject: radeon: bump driver date to know if lockup fix is in --- shared-core/radeon_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 71669c22..9e7d9a99 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -38,7 +38,7 @@ #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20080528" +#define DRIVER_DATE "20080613" /* Interface history: * -- cgit v1.2.3 From 29ffa0017d002f9e74de42817b962b6ca2e5f20a Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Fri, 13 Jun 2008 17:41:20 -0400 Subject: [FreeBSD] Fix another lock leak Reported by vehemens --- bsd-core/drm_bufs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bsd-core/drm_bufs.c b/bsd-core/drm_bufs.c index 3508331a..c793634b 100644 --- a/bsd-core/drm_bufs.c +++ b/bsd-core/drm_bufs.c @@ -832,12 +832,12 @@ int drm_addbufs_sg(struct drm_device *dev, drm_buf_desc_t *request) if (request->count < 0 || request->count > 4096) return EINVAL; - DRM_SPINLOCK(&dev->dma_lock); - order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL; + DRM_SPINLOCK(&dev->dma_lock); + /* No more allocations after first buffer-using ioctl. */ if (dev->buf_use != 0) { DRM_SPINUNLOCK(&dev->dma_lock); -- cgit v1.2.3 From 9dd58d6568702358bfb3d6d1b6459092cf77ae91 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 15 Jun 2008 18:49:47 +0200 Subject: radeon: fix screen corruption introduced by last patch --- shared-core/r300_cmdbuf.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index addc075d..91741628 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -649,9 +649,6 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, return r300_emit_bitblt_multi(dev_priv, cmdbuf); case RADEON_CP_INDX_BUFFER: - /* whenever we send vertex we clear flush & purge */ - dev_priv->track_flush ^= (RADEON_FLUSH_EMITED | - RADEON_PURGE_EMITED); /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ return r300_emit_indx_buffer(dev_priv, cmdbuf); case RADEON_CP_3D_DRAW_IMMD_2: @@ -660,11 +657,12 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ + /* whenever we send vertex we clear flush & purge */ + dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | + RADEON_PURGE_EMITED); + break; case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: - /* whenever we send vertex we clear flush & purge */ - dev_priv->track_flush ^= (RADEON_FLUSH_EMITED | - RADEON_PURGE_EMITED); /* these packets are safe */ break; default: -- cgit v1.2.3 From 6f8cc957034a887a9cbd576c1af9922862f6a7a7 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 15 Jun 2008 19:31:02 +0200 Subject: radeon: actualy try to fix the corruption --- shared-core/r300_cmdbuf.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index 91741628..eac15b0b 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -757,22 +757,27 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) { RING_LOCALS; + uint32_t cache_z, cache_3d, cache_2d; - if ((dev_priv->track_flush & RADEON_PURGE_EMITED)) { - /* purge already emited without vertex in btw don't purge - * again or lockup will likely happen */ - return; + cache_z = R300_ZC_FLUSH; + cache_2d = R300_RB2D_DC_FLUSH; + cache_3d = R300_RB3D_DC_FLUSH; + if (!(dev_priv->track_flush & RADEON_PURGE_EMITED)) { + /* we can purge, primitive where draw since last purge */ + cache_z |= R300_ZC_FREE; + cache_2d |= R300_RB2D_DC_FREE; + cache_3d |= R300_RB3D_DC_FREE; } /* flush & purge zbuffer */ BEGIN_RING(2); OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); - OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); + OUT_RING(cache_z); ADVANCE_RING(); /* flush & purge 3d */ BEGIN_RING(2); OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); - OUT_RING(R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE); + OUT_RING(cache_3d); ADVANCE_RING(); /* flush & purge texture */ BEGIN_RING(2); @@ -791,7 +796,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) /* flush & purge 2d through E2 as RB2D will trigger lockup */ BEGIN_RING(4); OUT_RING(CP_PACKET0(R300_DSTCACHE_CTLSTAT, 0)); - OUT_RING(R300_RB2D_DC_FLUSH | R300_RB2D_DC_FREE); + OUT_RING(cache_2d); OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); OUT_RING(RADEON_WAIT_2D_IDLECLEAN | RADEON_WAIT_HOST_IDLECLEAN); @@ -979,11 +984,8 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, DRM_DEBUG("\n"); - /* start by a wait, should be necessary */ - BEGIN_RING(2); - OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0)); - OUT_RING(RADEON_WAIT_3D_IDLE | RADEON_WAIT_2D_IDLE); - ADVANCE_RING(); + /* pacify */ + r300_pacify(dev_priv); if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) { ret = r300_emit_cliprects(dev_priv, cmdbuf, 0); -- cgit v1.2.3 From 59112c9e521d1543e8b76635ef223e7f29d35e6a Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Sun, 15 Jun 2008 20:18:29 +0200 Subject: radeon: *really* fix screen corruption thanks to Lukasz Krotowski --- shared-core/r300_cmdbuf.c | 1 - shared-core/radeon_cp.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index eac15b0b..cdb35d27 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -980,7 +980,6 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, struct drm_buf *buf = NULL; int emit_dispatch_age = 0; int ret = 0; - RING_LOCALS; DRM_DEBUG("\n"); diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index ec914df1..9b1ea855 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -442,7 +442,7 @@ static void radeon_do_cp_start(drm_radeon_private_t * dev_priv) OUT_RING(CP_PACKET0(RADEON_ISYNC_CNTL, 0)); OUT_RING(RADEON_ISYNC_ANY2D_IDLE3D | RADEON_ISYNC_ANY3D_IDLE2D | - RADEON_ISYNC_CPSCRATCH_IDLEGUI | + RADEON_ISYNC_WAIT_IDLEGUI | RADEON_ISYNC_CPSCRATCH_IDLEGUI); RADEON_PURGE_CACHE(); RADEON_PURGE_ZCACHE(); -- cgit v1.2.3 From 00f549bd5f40d9ad6ec7164cd01646ed468b9a4a Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Wed, 18 Jun 2008 14:19:38 +0800 Subject: i915: Add support for Intel 4 series chipsets Signed-off-by: Zhenyu Wang --- shared-core/drm_pciids.txt | 3 +++ shared-core/i915_drv.h | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index f48258a3..4e2cfb0e 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -395,6 +395,9 @@ 0x8086 0x29B2 CHIP_I9XX|CHIP_I915 "Intel Q35" 0x8086 0x29D2 CHIP_I9XX|CHIP_I915 "Intel Q33" 0x8086 0x2A42 CHIP_I9XX|CHIP_I965 "Intel Integrated Graphics Device" +0x8086 0x2E02 CHIP_I9XX|CHIP_I965 "Intel Integrated Graphics Device" +0x8086 0x2E12 CHIP_I9XX|CHIP_I965 "Intel Q45/Q43" +0x8086 0x2E22 CHIP_I9XX|CHIP_I965 "Intel G45/G43" [imagine] 0x105d 0x2309 IMAGINE_128 "Imagine 128" diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 427c49fe..32e90d29 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -1293,12 +1293,19 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); (dev)->pci_device == 0x29A2 || \ (dev)->pci_device == 0x2A02 || \ (dev)->pci_device == 0x2A12 || \ - (dev)->pci_device == 0x2A42) + (dev)->pci_device == 0x2A42 || \ + (dev)->pci_device == 0x2E02 || \ + (dev)->pci_device == 0x2E12 || \ + (dev)->pci_device == 0x2E22) #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02) #define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42) +#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ + (dev)->pci_device == 0x2E12 || \ + (dev)->pci_device == 0x2E22) + #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ (dev)->pci_device == 0x29B2 || \ (dev)->pci_device == 0x29D2) @@ -1309,7 +1316,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev)) -#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev)) +#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) -- cgit v1.2.3 From 8712f0a17bb135d4ad3eb85b30f47c561cf9c148 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 20 Jun 2008 12:03:41 +1000 Subject: drm: fix the ioctl to not believe userspace. believing userspace causes oopses --- linux-core/drm_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 609fc838..b375fa1b 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -631,6 +631,8 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err_i1; } #endif + cmd = ioctl->cmd; + func = ioctl->func; /* is there a local override? */ if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) -- cgit v1.2.3 From 9d79944a93e8e164e2261cdeb10cbd49ff8f314d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 20 Jun 2008 15:35:16 +1000 Subject: r300: fix warning --- shared-core/r300_cmdbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index cdb35d27..254c0691 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -756,8 +756,8 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv, */ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) { - RING_LOCALS; uint32_t cache_z, cache_3d, cache_2d; + RING_LOCALS; cache_z = R300_ZC_FLUSH; cache_2d = R300_RB2D_DC_FLUSH; -- cgit v1.2.3 From 1915de2c56d71bbd04a7c085cbd35fbe8e33af9d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 20 Jun 2008 15:35:47 +1000 Subject: drm: only use kernel ioctl cmd when doing a core ioctl. Need to overhaul the mess that is driver ioctls --- linux-core/drm_drv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index b375fa1b..6ac2adf3 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -613,9 +613,10 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; - else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) + else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { ioctl = &drm_ioctls[nr]; - else { + cmd = ioctl->cmd; + } else { retcode = -EINVAL; goto err_i1; } @@ -631,7 +632,6 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err_i1; } #endif - cmd = ioctl->cmd; func = ioctl->func; /* is there a local override? */ -- cgit v1.2.3 From 207f701e1affa18b0d54e09f7bf8b6447cb16258 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 21 Jun 2008 10:46:55 -0400 Subject: RADEON: 0x1002 0x5657 is actually an RV410 See bug 14289 --- shared-core/drm_pciids.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 4e2cfb0e..dd88ebab 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -79,7 +79,6 @@ 0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22" 0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C" 0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464" -0x1002 0x5657 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550XTX" 0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800" 0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro" 0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE" @@ -97,6 +96,7 @@ 0x1002 0x564F CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 XL M26" 0x1002 0x5652 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 M26" 0x1002 0x5653 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 M26" +0x1002 0x5657 CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon X550XTX" 0x1002 0x5834 CHIP_RS300|RADEON_IS_IGP "ATI Radeon RS300 9100 IGP" 0x1002 0x5835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS300 Mobility IGP" 0x1002 0x5954 CHIP_RS480|RADEON_IS_IGP|RADEON_IS_IGPGART "ATI RS480 XPRESS 200G" -- cgit v1.2.3 From 11f2a2ed6f854e7b461a98408df54167e9b9566d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 22 Jun 2008 18:25:22 +1000 Subject: agp: use true/false instead of TRUE/FALSE --- linux-core/drm_agpsupport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 0aa94a75..80663717 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -554,7 +554,7 @@ static int drm_agp_bind_ttm(struct drm_ttm_backend *backend, int snooped = (bo_mem->flags & DRM_BO_FLAG_CACHED) && !(bo_mem->flags & DRM_BO_FLAG_CACHED_MAPPED); DRM_DEBUG("drm_agp_bind_ttm\n"); - mem->is_flushed = TRUE; + mem->is_flushed = true; mem->type = AGP_USER_MEMORY; /* CACHED MAPPED implies not snooped memory */ if (snooped) @@ -653,7 +653,7 @@ struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev) agp_be->mem = NULL; agp_be->bridge = dev->agp->bridge; - agp_be->populated = FALSE; + agp_be->populated = false; agp_be->backend.func = &agp_ttm_backend; agp_be->backend.dev = dev; -- cgit v1.2.3 From b9ed0f995077f69ae806aae2e83085738ea5e651 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 01:00:42 +1000 Subject: nouveau: allocate drm-use vram buffers from end of vram. This avoids seeing garbage from engine setup etc before X gets around to pointing the CRTCs at a new scanout buffer. Not actually a noticable problem before G80 as PRAMIN is forced to the end of VRAM by the hardware already. --- shared-core/nouveau_drm.h | 4 ++- shared-core/nouveau_drv.h | 2 +- shared-core/nouveau_mem.c | 58 ++++++++++++++++++++++++++---------------- shared-core/nouveau_notifier.c | 2 +- shared-core/nouveau_object.c | 2 +- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index cf762052..bbb51bc4 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -88,9 +88,11 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ #define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ #define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ +#define NOUVEAU_MEM_USER 0x00001000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ - NOUVEAU_MEM_NOVM) + NOUVEAU_MEM_NOVM | \ + NOUVEAU_MEM_USER) struct drm_nouveau_mem_alloc { int flags; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index a51e552c..1aaf1d74 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -350,7 +350,7 @@ extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, uint64_t size); extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, uint64_t size, int align2, - struct drm_file *); + struct drm_file *, int tail); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); extern uint64_t nouveau_mem_fb_amount(struct drm_device *); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 2cf8807d..5511e5b6 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -35,8 +35,9 @@ #include "drm_sarea.h" #include "nouveau_drv.h" -static struct mem_block *split_block(struct mem_block *p, uint64_t start, uint64_t size, - struct drm_file *file_priv) +static struct mem_block * +split_block(struct mem_block *p, uint64_t start, uint64_t size, + struct drm_file *file_priv) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -77,10 +78,9 @@ out: return p; } -struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, - uint64_t size, - int align2, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, + int align2, struct drm_file *file_priv, int tail) { struct mem_block *p; uint64_t mask = (1 << align2) - 1; @@ -88,10 +88,22 @@ struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, if (!heap) return NULL; - list_for_each(p, heap) { - uint64_t start = (p->start + mask) & ~mask; - if (p->file_priv == 0 && start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); + if (tail) { + list_for_each_prev(p, heap) { + uint64_t start = ((p->start + p->size) - size) & ~mask; + + if (p->file_priv == 0 && start >= p->start && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } + } else { + list_for_each(p, heap) { + uint64_t start = (p->start + mask) & ~mask; + + if (p->file_priv == 0 && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } } return NULL; @@ -563,13 +575,13 @@ int nouveau_mem_init(struct drm_device *dev) return 0; } -struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, - uint64_t size, int flags, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, + int flags, struct drm_file *file_priv) { - struct mem_block *block; - int type; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct mem_block *block; + int type, tail = !(flags & NOUVEAU_MEM_USER); /* * Make things easier on ourselves: all allocations are page-aligned. @@ -600,14 +612,14 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, #define NOUVEAU_MEM_ALLOC_AGP {\ type=NOUVEAU_MEM_AGP;\ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\ - alignment, file_priv); \ + alignment, file_priv, tail); \ if (block) goto alloc_ok;\ } #define NOUVEAU_MEM_ALLOC_PCI {\ type = NOUVEAU_MEM_PCI;\ block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \ - alignment, file_priv); \ + alignment, file_priv, tail); \ if ( block ) goto alloc_ok;\ } @@ -616,11 +628,11 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, if (!(flags&NOUVEAU_MEM_MAPPED)) {\ block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\ size, alignment, \ - file_priv); \ + file_priv, tail); \ if (block) goto alloc_ok;\ }\ block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\ - alignment, file_priv);\ + alignment, file_priv, tail);\ if (block) goto alloc_ok;\ } @@ -738,7 +750,9 @@ out_free: * Ioctls */ -int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -748,8 +762,8 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file if (alloc->flags & NOUVEAU_MEM_INTERNAL) return -EINVAL; - block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size, - alloc->flags, file_priv); + block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size, + alloc->flags | NOUVEAU_MEM_USER, file_priv); if (!block) return -ENOMEM; alloc->map_handle=block->map_handle; diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 82c8ab7d..edece4da 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -94,7 +94,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, } mem = nouveau_mem_alloc_block(chan->notifier_heap, count*32, 0, - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!mem) { DRM_ERROR("Channel %d notifier block full\n", chan->id); return -ENOMEM; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 09f9027a..5664bfc8 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -248,7 +248,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; -- cgit v1.2.3 From 89cf2ee2e5b3930b36f2347f35933fc29bc42518 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 01:24:11 +1000 Subject: nv50: use same dma object for fb/tt access We depend on the VM fully now for memory protection, separate DMA objects for VRAM and GART are unneccesary. However, until the next interface break (soon) a client can't depend on the objects being the same and must still call NV_OBJ_SET_DMA_* methods appropriately. --- shared-core/nouveau_mem.c | 11 ++++++++++- shared-core/nouveau_object.c | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 5511e5b6..207d7860 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -754,6 +754,7 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -770,10 +771,15 @@ nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, alloc->offset=block->start; alloc->flags=block->flags; + if (dev_priv->card_type >= NV_50 && alloc->flags & NOUVEAU_MEM_FB) + alloc->offset += 512*1024*1024; + return 0; } -int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_mem_free *memfree = data; @@ -781,6 +787,9 @@ int nouveau_ioctl_mem_free(struct drm_device *dev, void *data, struct drm_file * NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + if (dev_priv->card_type >= NV_50 && memfree->flags & NOUVEAU_MEM_FB) + memfree->offset -= 512*1024*1024; + block=NULL; if (memfree->flags & NOUVEAU_MEM_FB) block = find_block(dev_priv->fb_heap, memfree->offset); diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 5664bfc8..894e7336 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -1036,8 +1036,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, /* VRAM ctxdma */ if (dev_priv->card_type >= NV_50) { ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 512*1024*1024, - dev_priv->fb_available_size, + 0, 0x100000000ULL, NV_DMA_ACCESS_RW, NV_DMA_TARGET_AGP, &vram); if (ret) { @@ -1059,6 +1058,9 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, } /* TT memory ctxdma */ + if (dev_priv->card_type >= NV_50) { + tt = vram; + } else if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { ret = nouveau_gpuobj_gart_dma_new(chan, 0, dev_priv->gart_info.aper_size, -- cgit v1.2.3 From 01e8f0ea426970859bafba72e067590df1a64eb0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 02:42:15 +1000 Subject: nv50: oops, keep VRAM allocations aligned at 64KiB - that's our page size.. --- shared-core/nouveau_mem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 207d7860..58942829 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -593,8 +593,11 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, /* Align allocation sizes to 64KiB blocks on G8x. We use a 64KiB * page size in the GPU VM. */ - if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) + if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) { size = (size + (64 * 1024)) & ~((64 * 1024) - 1); + if (alignment < 16) + alignment = 16; + } /* * Warn about 0 sized allocations, but let it go through. It'll return 1 page -- cgit v1.2.3 From 893cd01a1d6bed9740e9bfccde07f41ee401f898 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 24 Jun 2008 12:50:29 -0700 Subject: i915: register definition & header file cleanup It would be nice if one day the DRM driver was the canonical source for register definitions and core macros. To that end, this patch cleans things up quite a bit, removing redundant definitions (some with different names referring to the same register) and generally tidying up the header file. --- linux-core/i915_fence.c | 2 +- shared-core/i915_dma.c | 14 +- shared-core/i915_drv.h | 1791 ++++++++++++++++++++++++++++---------------- shared-core/i915_irq.c | 101 +-- shared-core/i915_suspend.c | 59 +- 5 files changed, 1232 insertions(+), 735 deletions(-) diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index e403be6a..45613c3a 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -46,7 +46,7 @@ static inline void i915_initiate_rwflush(struct drm_i915_private *dev_priv, dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fc->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW; } diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3f4fd1b2..27d152cb 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -40,11 +40,11 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_ring_buffer_t *ring = &(dev_priv->ring); - u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR; int i; for (i = 0; i < 10000; i++) { - ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -66,8 +66,8 @@ void i915_kernel_lost_context(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_ring_buffer_t *ring = &(dev_priv->ring); - ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR; - ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR; + ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; + ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->Size; @@ -516,7 +516,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) dev_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); - OUT_RING(CMD_STORE_DWORD_IDX); + OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); @@ -527,7 +527,7 @@ void i915_emit_breadcrumb(struct drm_device *dev) int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush) { drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t flush_cmd = CMD_MI_FLUSH; + uint32_t flush_cmd = MI_FLUSH; RING_LOCALS; flush_cmd |= flush; @@ -999,7 +999,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, dev_priv->hw_status_page = dev_priv->hws_map.handle; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); - I915_WRITE(0x02080, dev_priv->status_gfx_addr); + I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr); DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n", dev_priv->status_gfx_addr); DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 32e90d29..3ba74db8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -67,6 +67,11 @@ #endif #define DRIVER_PATCHLEVEL 0 +enum pipe { + PIPE_A = 0, + PIPE_B, +}; + #ifdef I915_HAVE_BUFFER #define I915_MAX_VALIDATE_BUFFERS 4096 struct drm_i915_validate_buffer; @@ -177,7 +182,7 @@ typedef struct drm_i915_private { u32 saveDSPASTRIDE; u32 saveDSPASIZE; u32 saveDSPAPOS; - u32 saveDSPABASE; + u32 saveDSPAADDR; u32 saveDSPASURF; u32 saveDSPATILEOFF; u32 savePFIT_PGM_RATIOS; @@ -198,24 +203,24 @@ typedef struct drm_i915_private { u32 saveDSPBSTRIDE; u32 saveDSPBSIZE; u32 saveDSPBPOS; - u32 saveDSPBBASE; + u32 saveDSPBADDR; u32 saveDSPBSURF; u32 saveDSPBTILEOFF; - u32 saveVCLK_DIVISOR_VGA0; - u32 saveVCLK_DIVISOR_VGA1; - u32 saveVCLK_POST_DIV; + u32 saveVGA0; + u32 saveVGA1; + u32 saveVGA_PD; u32 saveVGACNTRL; u32 saveADPA; u32 saveLVDS; - u32 saveLVDSPP_ON; - u32 saveLVDSPP_OFF; + u32 savePP_ON_DELAYS; + u32 savePP_OFF_DELAYS; u32 saveDVOA; u32 saveDVOB; u32 saveDVOC; u32 savePP_ON; u32 savePP_OFF; u32 savePP_CONTROL; - u32 savePP_CYCLE; + u32 savePP_DIVISOR; u32 savePFIT_CONTROL; u32 save_palette_a[256]; u32 save_palette_b[256]; @@ -228,7 +233,7 @@ typedef struct drm_i915_private { u32 saveIMR; u32 saveCACHE_MODE_0; u32 saveD_STATE; - u32 saveDSPCLK_GATE_D; + u32 saveCG_2D_DIS; u32 saveMI_ARB_STATE; u32 saveSWF0[16]; u32 saveSWF1[16]; @@ -357,6 +362,8 @@ typedef boolean_t bool; #define I915_VERBOSE 0 +#define PRIMARY_RINGBUFFER_SIZE (128*1024) + #define RING_LOCALS unsigned int outring, ringmask, outcount; \ volatile char *virt; @@ -384,13 +391,46 @@ typedef boolean_t bool; if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ dev_priv->ring.tail = outring; \ dev_priv->ring.space -= outcount * 4; \ - I915_WRITE(LP_RING + RING_TAIL, outring); \ + I915_WRITE(PRB0_TAIL, outring); \ } while(0) extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); -/* Extended config space */ -#define LBB 0xf4 +/* + * The Bridge device's PCI config space has information about the + * fb aperture size and the amount of pre-reserved memory. + */ +#define INTEL_GMCH_CTRL 0x52 +#define INTEL_GMCH_ENABLED 0x4 +#define INTEL_GMCH_MEM_MASK 0x1 +#define INTEL_GMCH_MEM_64M 0x1 +#define INTEL_GMCH_MEM_128M 0 + +#define INTEL_855_GMCH_GMS_MASK (0x7 << 4) +#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4) +#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4) + +#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4) +#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4) + +/* PCI config space */ + +#define HPLLCC 0xc0 /* 855 only */ +#define GC_CLOCK_CONTROL_MASK (3 << 0) +#define GC_CLOCK_133_200 (0 << 0) +#define GC_CLOCK_100_200 (1 << 0) +#define GC_CLOCK_100_133 (2 << 0) +#define GC_CLOCK_166_250 (3 << 0) +#define GCFGC 0xf0 /* 915+ only */ +#define GC_LOW_FREQUENCY_ENABLE (1 << 7) +#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4) +#define GC_DISPLAY_CLOCK_333_MHZ (4 << 4) +#define GC_DISPLAY_CLOCK_MASK (7 << 4) +#define LBB 0xf4 /* VGA stuff */ @@ -433,30 +473,167 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define VGA_CR_INDEX_CGA 0x3d4 #define VGA_CR_DATA_CGA 0x3d5 -#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) -#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) -#define CMD_REPORT_HEAD (7<<23) -#define CMD_STORE_DWORD_IMM ((0x20<<23) | (0x1 << 22) | 0x1) -#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) -#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) - -#define CMD_MI_FLUSH (0x04 << 23) -#define MI_NO_WRITE_FLUSH (1 << 2) -#define MI_READ_FLUSH (1 << 0) -#define MI_EXE_FLUSH (1 << 1) -#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ -#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ - -/* Packet to load a register value from the ring/batch command stream: +/* + * Memory interface instructions used by the kernel + */ +#define MI_INSTR(opcode, flags) (((opcode) << 23) | (flags)) + +#define MI_NOOP MI_INSTR(0, 0) +#define MI_USER_INTERRUPT MI_INSTR(0x02, 0) +#define MI_WAIT_FOR_EVENT MI_INSTR(0x03, 0) +#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) +#define MI_FLUSH MI_INSTR(0x04, 0) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_SCENE_COUNT (1 << 3) /* just increment scene count */ +#define MI_END_SCENE (1 << 4) /* flush binner and incr scene count */ +#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0) +#define MI_REPORT_HEAD MI_INSTR(0x07, 0) +#define MI_LOAD_SCAN_LINES_INCL MI_INSTR(0x12, 0) +#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1) +#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */ +#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1) +#define MI_LOAD_REGISTER_IMM MI_INSTR(0x22, 1) +#define MI_BATCH_BUFFER MI_INSTR(0x30, 1) +#define MI_BATCH_NON_SECURE (1) +#define MI_BATCH_NON_SECURE_I965 (1<<8) +#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) + +#define BREADCRUMB_BITS 31 +#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) + +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) + +/** + * 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: + * 0: ISR copy, updated when an ISR bit not set in the HWSTAM changes. + * 4: ring 0 head pointer + * 5: ring 1 head pointer (915-class) + * 6: ring 2 head pointer (915-class) + * + * The area from dword 0x10 to 0x3ff is available for driver usage. + */ +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) +#define I915_GEM_HWS_INDEX 0x10 + +/* + * 3D instructions used by the kernel + */ +#define GFX_INSTR(opcode, flags) ((0x3 << 29) | ((opcode) << 24) | (flags)) + +#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) +#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR (0x1<<1) +#define SC_ENABLE_MASK (0x1<<0) +#define SC_ENABLE (0x1<<0) +#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) +#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK (0xffff<<16) +#define SCI_XMIN_MASK (0xffff<<0) +#define SCI_YMAX_MASK (0xffff<<16) +#define SCI_XMAX_MASK (0xffff<<0) +#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) +#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) +#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) +#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) +#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_MONO_SRC_COPY_IMM_BLT ((2<<29)|(0x71<<22)|5) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) +#define BLT_DEPTH_8 (0<<24) +#define BLT_DEPTH_16_565 (1<<24) +#define BLT_DEPTH_16_1555 (2<<24) +#define BLT_DEPTH_32 (3<<24) +#define BLT_ROP_GXCOPY (0xcc<<16) +#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) /* 965+ only */ +#define XY_SRC_COPY_BLT_DST_TILED (1<<11) /* 965+ only */ +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) +#define DISPLAY_PLANE_A (0<<20) +#define DISPLAY_PLANE_B (1<<20) + +/* + * Instruction and interrupt control regs */ -#define CMD_MI_LOAD_REGISTER_IMM ((0x22 << 23)|0x1) -#define BB1_START_ADDR_MASK (~0x7) -#define BB1_PROTECTED (1<<0) -#define BB1_UNPROTECTED (0<<0) -#define BB2_END_ADDR_MASK (~0x7) +#define PRB0_TAIL 0x02030 +#define PRB0_HEAD 0x02034 +#define PRB0_START 0x02038 +#define PRB0_CTL 0x0203c +#define TAIL_ADDR 0x001FFFF8 +#define HEAD_WRAP_COUNT 0xFFE00000 +#define HEAD_WRAP_ONE 0x00200000 +#define HEAD_ADDR 0x001FFFFC +#define RING_NR_PAGES 0x001FF000 +#define RING_REPORT_MASK 0x00000006 +#define RING_REPORT_64K 0x00000002 +#define RING_REPORT_128K 0x00000004 +#define RING_NO_REPORT 0x00000000 +#define RING_VALID_MASK 0x00000001 +#define RING_VALID 0x00000001 +#define RING_INVALID 0x00000000 +#define PRB1_TAIL 0x02040 /* 915+ only */ +#define PRB1_HEAD 0x02044 /* 915+ only */ +#define PRB1_START 0x02048 /* 915+ only */ +#define PRB1_CTL 0x0204c /* 915+ only */ +#define HWS_PGA 0x02080 +#define IPEIR 0x02088 +#define NOPID 0x02094 +#define HWSTAM 0x02098 +#define SCPD0 0x0209c /* 915+ only */ +#define IER 0x020a0 +#define IIR 0x020a4 +#define IMR 0x020a8 +#define ISR 0x020ac +#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) +#define I915_DISPLAY_PORT_INTERRUPT (1<<17) +#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) +#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) +#define I915_HWB_OOM_INTERRUPT (1<<13) +#define I915_SYNC_STATUS_INTERRUPT (1<<12) +#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) +#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) +#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) +#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) +#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) +#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) +#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) +#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) +#define I915_DEBUG_INTERRUPT (1<<2) +#define I915_USER_INTERRUPT (1<<1) +#define EIR 0x020b0 +#define EMR 0x020b4 +#define ESR 0x020b8 +#define INSTPM 0x020c0 +#define FW_BLC 0x020d8 +#define FW_BLC_SELF 0x020e0 /* 915+ only */ +#define MI_ARB_STATE 0x020e4 /* 915+ only */ +#define CACHE_MODE_0 0x02120 /* 915+ only */ +#define CM0_MASK_SHIFT 16 +#define CM0_IZ_OPT_DISABLE (1<<6) +#define CM0_ZR_OPT_DISABLE (1<<5) +#define CM0_DEPTH_EVICT_DISABLE (1<<4) +#define CM0_COLOR_EVICT_DISABLE (1<<3) +#define CM0_DEPTH_WRITE_DISABLE (1<<1) +#define CM0_RC_OP_FLUSH_DISABLE (1<<0) +#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ + +/* + * Framebuffer compression (915+ only) + */ -/* Framebuffer compression */ #define FBC_CFB_BASE 0x03200 /* 4k page aligned */ #define FBC_LL_BASE 0x03204 /* 4k page aligned */ #define FBC_CONTROL 0x03208 @@ -485,69 +662,64 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define FBC_FENCE_OFF 0x0321b #define FBC_LL_SIZE (1536) -#define FBC_LL_PAD (32) -/* Interrupt bits: +/* + * GPIO regs */ -#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) -#define I915_DISPLAY_PORT_INTERRUPT (1<<17) -#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) -#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) -#define I915_HWB_OOM_INTERRUPT (1<<13) /* binner out of memory */ -#define I915_SYNC_STATUS_INTERRUPT (1<<12) -#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11) -#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10) -#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9) -#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8) -#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7) -#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6) -#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5) -#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) -#define I915_DEBUG_INTERRUPT (1<<2) -#define I915_USER_INTERRUPT (1<<1) - - -#define I915REG_HWSTAM 0x02098 -#define I915REG_INT_IDENTITY_R 0x020a4 -#define I915REG_INT_MASK_R 0x020a8 -#define I915REG_INT_ENABLE_R 0x020a0 -#define I915REG_INSTPM 0x020c0 -#define PIPEADSL 0x70000 -#define PIPEBDSL 0x71000 +#define GPIOA 0x5010 +#define GPIOB 0x5014 +#define GPIOC 0x5018 +#define GPIOD 0x501c +#define GPIOE 0x5020 +#define GPIOF 0x5024 +#define GPIOG 0x5028 +#define GPIOH 0x502c +# define GPIO_CLOCK_DIR_MASK (1 << 0) +# define GPIO_CLOCK_DIR_IN (0 << 1) +# define GPIO_CLOCK_DIR_OUT (1 << 1) +# define GPIO_CLOCK_VAL_MASK (1 << 2) +# define GPIO_CLOCK_VAL_OUT (1 << 3) +# define GPIO_CLOCK_VAL_IN (1 << 4) +# define GPIO_CLOCK_PULLUP_DISABLE (1 << 5) +# define GPIO_DATA_DIR_MASK (1 << 8) +# define GPIO_DATA_DIR_IN (0 << 9) +# define GPIO_DATA_DIR_OUT (1 << 9) +# define GPIO_DATA_VAL_MASK (1 << 10) +# define GPIO_DATA_VAL_OUT (1 << 11) +# define GPIO_DATA_VAL_IN (1 << 12) +# define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#define I915REG_PIPEASTAT 0x70024 -#define I915REG_PIPEBSTAT 0x71024 /* - * The two pipe frame counter registers are not synchronized, so - * reading a stable value is somewhat tricky. The following code - * should work: - * - * do { - * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT; - * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> - * PIPE_FRAME_LOW_SHIFT); - * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> - * PIPE_FRAME_HIGH_SHIFT); - * } while (high1 != high2); - * frame = (high1 << 8) | low1; + * Clock control & power management */ -#define PIPEAFRAMEHIGH 0x70040 -#define PIPEBFRAMEHIGH 0x71040 -#define PIPE_FRAME_HIGH_MASK 0x0000ffff -#define PIPE_FRAME_HIGH_SHIFT 0 -#define PIPEAFRAMEPIXEL 0x70044 -#define PIPEBFRAMEPIXEL 0x71044 -#define PIPE_FRAME_LOW_MASK 0xff000000 -#define PIPE_FRAME_LOW_SHIFT 24 -/* - * Pixel within the current frame is counted in the PIPEAFRAMEPIXEL register - * and is 24 bits wide. - */ -#define PIPE_PIXEL_MASK 0x00ffffff -#define PIPE_PIXEL_SHIFT 0 +#define VGA0 0x6000 +#define VGA1 0x6004 +#define VGA_PD 0x6010 +#define VGA0_PD_P2_DIV_4 (1 << 7) +#define VGA0_PD_P1_DIV_2 (1 << 5) +#define VGA0_PD_P1_SHIFT 0 +#define VGA0_PD_P1_MASK (0x1f << 0) +#define VGA1_PD_P2_DIV_4 (1 << 15) +#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_VCO_ENABLE (1 << 31) +#define DPLL_DVO_HIGH_SPEED (1 << 30) +#define DPLL_SYNCLOCK_ENABLE (1 << 29) +#define DPLL_VGA_MODE_DIS (1 << 28) +#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ +#define DPLLB_MODE_LVDS (2 << 26) /* i915 */ +#define DPLL_MODE_MASK (3 << 26) +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ +#define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ +#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ +#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ +#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define I915_FIFO_UNDERRUN_STATUS (1UL<<31) #define I915_CRC_ERROR_ENABLE (1UL<<29) @@ -597,13 +769,6 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define ADPA_DPMS_STANDBY (2<<10) #define ADPA_DPMS_OFF (3<<10) -#define NOPID 0x2094 -#define LP_RING 0x2030 -#define HP_RING 0x2040 -/* The binner has its own ring buffer: - */ -#define HWB_RING 0x2400 - #define RING_TAIL 0x00 #define TAIL_ADDR 0x001FFFF8 #define RING_HEAD 0x04 @@ -622,234 +787,127 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define RING_VALID 0x00000001 #define RING_INVALID 0x00000000 -/* Instruction parser error reg: - */ -#define IPEIR 0x2088 - /* Scratch pad debug 0 reg: */ -#define SCPD0 0x209c - -/* Error status reg: +#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +/* + * The i830 generation, in LVDS mode, defines P1 as the bit number set within + * this field (only one bit may be set). */ -#define ESR 0x20b8 - -/* Secondary DMA fetch address debug reg: +#define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 +#define DPLL_FPA01_P1_POST_DIV_SHIFT 16 +/* i830, required in DVO non-gang */ +#define PLL_P2_DIVIDE_BY_4 (1 << 23) +#define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ +#define PLL_REF_INPUT_DREFCLK (0 << 13) +#define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ +#define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ +#define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) +#define PLL_REF_INPUT_MASK (3 << 13) +#define PLL_LOAD_PULSE_PHASE_SHIFT 9 +/* + * Parallel to Serial Load Pulse phase selection. + * Selects the phase for the 10X DPLL clock for the PCIe + * digital display port. The range is 4 to 13; 10 or more + * is just a flip delay. The default is 6 */ -#define DMA_FADD_S 0x20d4 - -/* Memory Interface Arbitration State +#define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) +#define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +/* + * SDVO multiplier for 945G/GM. Not used on 965. */ -#define MI_ARB_STATE 0x20e4 - -/* Cache mode 0 reg. - * - Manipulating render cache behaviour is central - * to the concept of zone rendering, tuning this reg can help avoid - * unnecessary render cache reads and even writes (for z/stencil) - * at beginning and end of scene. +#define SDVO_MULTIPLIER_MASK 0x000000ff +#define SDVO_MULTIPLIER_SHIFT_HIRES 4 +#define SDVO_MULTIPLIER_SHIFT_VGA 0 +#define DPLL_A_MD 0x0601c /* 965+ only */ +/* + * UDI pixel divider, controlling how many pixels are stuffed into a packet. * - * - To change a bit, write to this reg with a mask bit set and the - * bit of interest either set or cleared. EG: (BIT<<16) | BIT to set. - */ -#define Cache_Mode_0 0x2120 -#define CACHE_MODE_0 0x2120 -#define CM0_MASK_SHIFT 16 -#define CM0_IZ_OPT_DISABLE (1<<6) -#define CM0_ZR_OPT_DISABLE (1<<5) -#define CM0_DEPTH_EVICT_DISABLE (1<<4) -#define CM0_COLOR_EVICT_DISABLE (1<<3) -#define CM0_DEPTH_WRITE_DISABLE (1<<1) -#define CM0_RC_OP_FLUSH_DISABLE (1<<0) - - -/* Graphics flush control. A CPU write flushes the GWB of all writes. - * The data is discarded. - */ -#define GFX_FLSH_CNTL 0x2170 - -/* Binner control. Defines the location of the bin pointer list: - */ -#define BINCTL 0x2420 -#define BC_MASK (1 << 9) - -/* Binned scene info. - */ -#define BINSCENE 0x2428 -#define BS_OP_LOAD (1 << 8) -#define BS_MASK (1 << 22) - -/* Bin command parser debug reg: - */ -#define BCPD 0x2480 - -/* Bin memory control debug reg: - */ -#define BMCD 0x2484 - -/* Bin data cache debug reg: - */ -#define BDCD 0x2488 - -/* Binner pointer cache debug reg: - */ -#define BPCD 0x248c - -/* Binner scratch pad debug reg: - */ -#define BINSKPD 0x24f0 - -/* HWB scratch pad debug reg: + * Value is pixels minus 1. Must be set to 1 pixel for SDVO. */ -#define HWBSKPD 0x24f4 - -/* Binner memory pool reg: +#define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 +#define DPLL_MD_UDI_DIVIDER_SHIFT 24 +/* UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ +#define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 +#define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +/* + * SDVO/UDI pixel multiplier. + * + * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus + * clock rate is 10 times the DPLL clock. At low resolution/refresh rate + * modes, the bus rate would be below the limits, so SDVO allows for stuffing + * dummy bytes in the datastream at an increased clock rate, with both sides of + * the link knowing how many bytes are fill. + * + * So, for a mode with a dotclock of 65Mhz, we would want to double the clock + * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be + * set to 130Mhz, and the SDVO multiplier set to 2x in this register and + * through an SDVO command. + * + * This register field has values of multiplication factor minus 1, with + * a maximum multiplier of 5 for SDVO. */ -#define BMP_BUFFER 0x2430 -#define BMP_PAGE_SIZE_4K (0 << 10) -#define BMP_BUFFER_SIZE_SHIFT 1 -#define BMP_ENABLE (1 << 0) - -/* Get/put memory from the binner memory pool: +#define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 +#define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 +/* + * SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. + * This best be set to the default value (3) or the CRT won't work. No, + * I don't entirely understand what this does... */ -#define BMP_GET 0x2438 -#define BMP_PUT 0x2440 -#define BMP_OFFSET_SHIFT 5 +#define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f +#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 +#define DPLL_B_MD 0x06020 /* 965+ only */ +#define FPA0 0x06040 +#define FPA1 0x06044 +#define FPB0 0x06048 +#define FPB1 0x0604c +#define FP_N_DIV_MASK 0x003f0000 +#define FP_N_DIV_SHIFT 16 +#define FP_M1_DIV_MASK 0x00003f00 +#define FP_M1_DIV_SHIFT 8 +#define FP_M2_DIV_MASK 0x0000003f +#define FP_M2_DIV_SHIFT 0 +#define DPLL_TEST 0x606c +#define DPLLB_TEST_SDVO_DIV_1 (0 << 22) +#define DPLLB_TEST_SDVO_DIV_2 (1 << 22) +#define DPLLB_TEST_SDVO_DIV_4 (2 << 22) +#define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) +#define DPLLB_TEST_N_BYPASS (1 << 19) +#define DPLLB_TEST_M_BYPASS (1 << 18) +#define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) +#define DPLLA_TEST_N_BYPASS (1 << 3) +#define DPLLA_TEST_M_BYPASS (1 << 2) +#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) +#define D_STATE 0x6104 +#define CG_2D_DIS 0x6200 +#define CG_3D_DIS 0x6204 -/* 3D state packets: +/* + * Palette regs */ -#define GFX_OP_RASTER_RULES ((0x3<<29)|(0x7<<24)) - -#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define SC_UPDATE_SCISSOR (0x1<<1) -#define SC_ENABLE_MASK (0x1<<0) -#define SC_ENABLE (0x1<<0) - -#define GFX_OP_LOAD_INDIRECT ((0x3<<29)|(0x1d<<24)|(0x7<<16)) - -#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) -#define SCI_YMIN_MASK (0xffff<<16) -#define SCI_XMIN_MASK (0xffff<<0) -#define SCI_YMAX_MASK (0xffff<<16) -#define SCI_XMAX_MASK (0xffff<<0) - -#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19)) -#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1) -#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0) -#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) -#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4) -#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0) -#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3)) - -#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) - -#define SRC_COPY_BLT_CMD ((2<<29)|(0x43<<22)|4) -#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) -#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) -#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) -#define XY_SRC_COPY_BLT_SRC_TILED (1<<15) -#define XY_SRC_COPY_BLT_DST_TILED (1<<11) - - -#define MI_BATCH_BUFFER ((0x30<<23)|1) -#define MI_BATCH_BUFFER_START (0x31<<23) -#define MI_BATCH_BUFFER_END (0xA<<23) -#define MI_BATCH_NON_SECURE (1) - -#define MI_BATCH_NON_SECURE_I965 (1<<8) - -#define MI_WAIT_FOR_EVENT ((0x3<<23)) -#define MI_WAIT_FOR_PLANE_B_FLIP (1<<6) -#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) -#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) -#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23)) - -#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) -#define ASYNC_FLIP (1<<22) -#define DISPLAY_PLANE_A (0<<20) -#define DISPLAY_PLANE_B (1<<20) - -/* Display regs */ -#define DSPACNTR 0x70180 -#define DSPBCNTR 0x71180 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define PALETTE_A 0x0a000 +#define PALETTE_B 0x0a800 -/* Define the region of interest for the binner: +/* + * Overlay regs */ -#define CMD_OP_BIN_CONTROL ((0x3<<29)|(0x1d<<24)|(0x84<<16)|4) - -#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) - -#define BREADCRUMB_BITS 31 -#define BREADCRUMB_MASK ((1U << BREADCRUMB_BITS) - 1) - -#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) -#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) -#define BLC_PWM_CTL 0x61254 -#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +#define OVADD 0x30000 +#define DOVSTA 0x30008 +#define OC_BUF (0x3<<20) +#define OGAMC5 0x30010 +#define OGAMC4 0x30014 +#define OGAMC3 0x30018 +#define OGAMC2 0x3001c +#define OGAMC1 0x30020 +#define OGAMC0 0x30024 -#define BLC_PWM_CTL2 0x61250 -/** - * 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. - * - * This field must be no greater than the number of cycles in the complete - * backlight modulation cycle. - */ -#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) -#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) - -#define I915_GCFGC 0xf0 -#define I915_LOW_FREQUENCY_ENABLE (1 << 7) -#define I915_DISPLAY_CLOCK_190_200_MHZ (0 << 4) -#define I915_DISPLAY_CLOCK_333_MHZ (4 << 4) -#define I915_DISPLAY_CLOCK_MASK (7 << 4) - -#define I855_HPLLCC 0xc0 -#define I855_CLOCK_CONTROL_MASK (3 << 0) -#define I855_CLOCK_133_200 (0 << 0) -#define I855_CLOCK_100_200 (1 << 0) -#define I855_CLOCK_100_133 (2 << 0) -#define I855_CLOCK_166_250 (3 << 0) - -/* p317, 319 +/* + * Display engine regs */ -#define VCLK2_VCO_M 0x6008 /* treat as 16 bit? (includes msbs) */ -#define VCLK2_VCO_N 0x600a -#define VCLK2_VCO_DIV_SEL 0x6012 - -#define VCLK_DIVISOR_VGA0 0x6000 -#define VCLK_DIVISOR_VGA1 0x6004 -#define VCLK_POST_DIV 0x6010 -/** Selects a post divisor of 4 instead of 2. */ -# define VGA1_PD_P2_DIV_4 (1 << 15) -/** Overrides the p2 post divisor field */ -# define VGA1_PD_P1_DIV_2 (1 << 13) -# define VGA1_PD_P1_SHIFT 8 -/** P1 value is 2 greater than this field */ -# define VGA1_PD_P1_MASK (0x1f << 8) -/** Selects a post divisor of 4 instead of 2. */ -# define VGA0_PD_P2_DIV_4 (1 << 7) -/** Overrides the p2 post divisor field */ -# define VGA0_PD_P1_DIV_2 (1 << 5) -# define VGA0_PD_P1_SHIFT 0 -/** P1 value is 2 greater than this field */ -# define VGA0_PD_P1_MASK (0x1f << 0) - -/* PCI D state control register */ -#define D_STATE 0x6104 -#define DSPCLK_GATE_D 0x6200 -/* I830 CRTC registers */ +/* Pipe A timing regs */ #define HTOTAL_A 0x60000 #define HBLANK_A 0x60004 #define HSYNC_A 0x60008 @@ -858,8 +916,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define VSYNC_A 0x60014 #define PIPEASRC 0x6001c #define BCLRPAT_A 0x60020 -#define VSYNCSHIFT_A 0x60028 +/* Pipe B timing regs */ #define HTOTAL_B 0x61000 #define HBLANK_B 0x61004 #define HSYNC_B 0x61008 @@ -868,413 +926,856 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define VSYNC_B 0x61014 #define PIPEBSRC 0x6101c #define BCLRPAT_B 0x61020 -#define VSYNCSHIFT_B 0x61028 -#define HACTIVE_MASK 0x00000fff -#define VTOTAL_MASK 0x00001fff -#define VTOTAL_SHIFT 16 -#define VACTIVE_MASK 0x00000fff -#define VBLANK_END_MASK 0x00001fff -#define VBLANK_END_SHIFT 16 -#define VBLANK_START_MASK 0x00001fff +/* VGA port control */ +#define ADPA 0x61100 +#define ADPA_DAC_ENABLE (1<<31) +#define ADPA_DAC_DISABLE 0 +#define ADPA_PIPE_SELECT_MASK (1<<30) +#define ADPA_PIPE_A_SELECT 0 +#define ADPA_PIPE_B_SELECT (1<<30) +#define ADPA_USE_VGA_HVPOLARITY (1<<15) +#define ADPA_SETS_HVPOLARITY 0 +#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_ENABLE 0 +#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_ENABLE 0 +#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) +#define ADPA_VSYNC_ACTIVE_LOW 0 +#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) +#define ADPA_HSYNC_ACTIVE_LOW 0 +#define ADPA_DPMS_MASK (~(3<<10)) +#define ADPA_DPMS_ON (0<<10) +#define ADPA_DPMS_SUSPEND (1<<10) +#define ADPA_DPMS_STANDBY (2<<10) +#define ADPA_DPMS_OFF (3<<10) + +/* Hotplug control (945+ only) */ +#define PORT_HOTPLUG_EN 0x61110 +#define SDVOB_HOTPLUG_INT_EN (1 << 26) +#define SDVOC_HOTPLUG_INT_EN (1 << 25) +#define TV_HOTPLUG_INT_EN (1 << 18) +#define CRT_HOTPLUG_INT_EN (1 << 9) +#define CRT_HOTPLUG_FORCE_DETECT (1 << 3) -#define PP_STATUS 0x61200 -# define PP_ON (1 << 31) +#define PORT_HOTPLUG_STAT 0x61114 +#define CRT_HOTPLUG_INT_STATUS (1 << 11) +#define TV_HOTPLUG_INT_STATUS (1 << 10) +#define CRT_HOTPLUG_MONITOR_MASK (3 << 8) +#define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) +#define CRT_HOTPLUG_MONITOR_MONO (2 << 8) +#define CRT_HOTPLUG_MONITOR_NONE (0 << 8) +#define SDVOC_HOTPLUG_INT_STATUS (1 << 7) +#define SDVOB_HOTPLUG_INT_STATUS (1 << 6) + +/* SDVO port control */ +#define SDVOB 0x61140 +#define SDVOC 0x61160 +#define SDVO_ENABLE (1 << 31) +#define SDVO_PIPE_B_SELECT (1 << 30) +#define SDVO_STALL_SELECT (1 << 29) +#define SDVO_INTERRUPT_ENABLE (1 << 26) /** + * 915G/GM SDVO pixel multiplier. + * + * Programmed value is multiplier - 1, up to 5x. + * + * \sa DPLL_MD_UDI_MULTIPLIER_MASK + */ +#define SDVO_PORT_MULTIPLY_MASK (7 << 23) +#define SDVO_PORT_MULTIPLY_SHIFT 23 +#define SDVO_PHASE_SELECT_MASK (15 << 19) +#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) +#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) +#define SDVOC_GANG_MODE (1 << 16) +#define SDVO_BORDER_ENABLE (1 << 7) +#define SDVOB_PCIE_CONCURRENCY (1 << 3) +#define SDVO_DETECTED (1 << 2) +/* Bits to be preserved when writing */ +#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14) | (1 << 26)) +#define SDVOC_PRESERVE_MASK ((1 << 17) | (1 << 26)) + +/* DVO port control */ +#define DVOA 0x61120 +#define DVOB 0x61140 +#define DVOC 0x61160 +#define DVO_ENABLE (1 << 31) +#define DVO_PIPE_B_SELECT (1 << 30) +#define DVO_PIPE_STALL_UNUSED (0 << 28) +#define DVO_PIPE_STALL (1 << 28) +#define DVO_PIPE_STALL_TV (2 << 28) +#define DVO_PIPE_STALL_MASK (3 << 28) +#define DVO_USE_VGA_SYNC (1 << 15) +#define DVO_DATA_ORDER_I740 (0 << 14) +#define DVO_DATA_ORDER_FP (1 << 14) +#define DVO_VSYNC_DISABLE (1 << 11) +#define DVO_HSYNC_DISABLE (1 << 10) +#define DVO_VSYNC_TRISTATE (1 << 9) +#define DVO_HSYNC_TRISTATE (1 << 8) +#define DVO_BORDER_ENABLE (1 << 7) +#define DVO_DATA_ORDER_GBRG (1 << 6) +#define DVO_DATA_ORDER_RGGB (0 << 6) +#define DVO_DATA_ORDER_GBRG_ERRATA (0 << 6) +#define DVO_DATA_ORDER_RGGB_ERRATA (1 << 6) +#define DVO_VSYNC_ACTIVE_HIGH (1 << 4) +#define DVO_HSYNC_ACTIVE_HIGH (1 << 3) +#define DVO_BLANK_ACTIVE_HIGH (1 << 2) +#define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ +#define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ +#define DVO_PRESERVE_MASK (0x7<<24) +#define DVOA_SRCDIM 0x61124 +#define DVOB_SRCDIM 0x61144 +#define DVOC_SRCDIM 0x61164 +#define DVO_SRCDIM_HORIZONTAL_SHIFT 12 +#define DVO_SRCDIM_VERTICAL_SHIFT 0 + +/* LVDS port control */ +#define LVDS 0x61180 +/* + * Enables the LVDS port. This bit must be set before DPLLs are enabled, as + * the DPLL semantics change when the LVDS is assigned to that pipe. + */ +#define LVDS_PORT_EN (1 << 31) +/* Selects pipe B for LVDS data. Must be set on pre-965. */ +#define LVDS_PIPEB_SELECT (1 << 30) +/* + * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per + * pixel. + */ +#define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) +#define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) +#define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +/* + * Controls the A3 data pair, which contains the additional LSBs for 24 bit + * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be + * on. + */ +#define LVDS_A3_POWER_MASK (3 << 6) +#define LVDS_A3_POWER_DOWN (0 << 6) +#define LVDS_A3_POWER_UP (3 << 6) +/* + * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP + * is set. + */ +#define LVDS_CLKB_POWER_MASK (3 << 4) +#define LVDS_CLKB_POWER_DOWN (0 << 4) +#define LVDS_CLKB_POWER_UP (3 << 4) +/* + * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 + * setting for whether we are in dual-channel mode. The B3 pair will + * additionally only be powered up when LVDS_A3_POWER_UP is set. + */ +#define LVDS_B0B3_POWER_MASK (3 << 2) +#define LVDS_B0B3_POWER_DOWN (0 << 2) +#define LVDS_B0B3_POWER_UP (3 << 2) + +/* Panel power sequencing */ +#define PP_STATUS 0x61200 +#define PP_ON (1 << 31) +/* * Indicates that all dependencies of the panel are on: * * - PLL enabled * - pipe enabled * - LVDS/DVOB/DVOC on */ -# define PP_READY (1 << 30) -# define PP_SEQUENCE_NONE (0 << 28) -# define PP_SEQUENCE_ON (1 << 28) -# define PP_SEQUENCE_OFF (2 << 28) -# define PP_SEQUENCE_MASK 0x30000000 +#define PP_READY (1 << 30) +#define PP_SEQUENCE_NONE (0 << 28) +#define PP_SEQUENCE_ON (1 << 28) +#define PP_SEQUENCE_OFF (2 << 28) +#define PP_SEQUENCE_MASK 0x30000000 #define PP_CONTROL 0x61204 -# define POWER_TARGET_ON (1 << 0) - -#define LVDSPP_ON 0x61208 -#define LVDSPP_OFF 0x6120c -#define PP_CYCLE 0x61210 +#define POWER_TARGET_ON (1 << 0) +#define PP_ON_DELAYS 0x61208 +#define PP_OFF_DELAYS 0x6120c +#define PP_DIVISOR 0x61210 +/* Panel fitting */ #define PFIT_CONTROL 0x61230 -# define PFIT_ENABLE (1 << 31) -# define PFIT_PIPE_MASK (3 << 29) -# define PFIT_PIPE_SHIFT 29 -# define VERT_INTERP_DISABLE (0 << 10) -# define VERT_INTERP_BILINEAR (1 << 10) -# define VERT_INTERP_MASK (3 << 10) -# define VERT_AUTO_SCALE (1 << 9) -# define HORIZ_INTERP_DISABLE (0 << 6) -# define HORIZ_INTERP_BILINEAR (1 << 6) -# define HORIZ_INTERP_MASK (3 << 6) -# define HORIZ_AUTO_SCALE (1 << 5) -# define PANEL_8TO6_DITHER_ENABLE (1 << 3) - +#define PFIT_ENABLE (1 << 31) +#define PFIT_PIPE_MASK (3 << 29) +#define PFIT_PIPE_SHIFT 29 +#define VERT_INTERP_DISABLE (0 << 10) +#define VERT_INTERP_BILINEAR (1 << 10) +#define VERT_INTERP_MASK (3 << 10) +#define VERT_AUTO_SCALE (1 << 9) +#define HORIZ_INTERP_DISABLE (0 << 6) +#define HORIZ_INTERP_BILINEAR (1 << 6) +#define HORIZ_INTERP_MASK (3 << 6) +#define HORIZ_AUTO_SCALE (1 << 5) +#define PANEL_8TO6_DITHER_ENABLE (1 << 3) #define PFIT_PGM_RATIOS 0x61234 -# define PFIT_VERT_SCALE_MASK 0xfff00000 -# define PFIT_HORIZ_SCALE_MASK 0x0000fff0 - -#define PFIT_AUTO_RATIOS 0x61238 - - -#define DPLL_A 0x06014 -#define DPLL_B 0x06018 -# define DPLL_VCO_ENABLE (1 << 31) -# define DPLL_DVO_HIGH_SPEED (1 << 30) -# define DPLL_SYNCLOCK_ENABLE (1 << 29) -# define DPLL_VGA_MODE_DIS (1 << 28) -# define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ -# define DPLLB_MODE_LVDS (2 << 26) /* i915 */ -# define DPLL_MODE_MASK (3 << 26) -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10 (0 << 24) /* i915 */ -# define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 (1 << 24) /* i915 */ -# define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */ -# define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */ -# define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */ -# define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ -/** - * The i830 generation, in DAC/serial mode, defines p1 as two plus this - * bitfield, or just 2 if PLL_P1_DIVIDE_BY_TWO is set. +#define PFIT_VERT_SCALE_MASK 0xfff00000 +#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +#define PFIT_AUTO_RATIOS 0x61238 + +/* Backlight control */ +#define BLC_PWM_CTL 0x61254 +#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) +#define BLC_PWM_CTL2 0x61250 /* 965+ only */ +/* + * 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. + * + * This field must be no greater than the number of cycles in the complete + * backlight modulation cycle. */ -# define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 +#define BACKLIGHT_DUTY_CYCLE_SHIFT (0) +#define BACKLIGHT_DUTY_CYCLE_MASK (0xffff) + +/* TV port control */ +#define TV_CTL 0x68000 +/** Enables the TV encoder */ +# define TV_ENC_ENABLE (1 << 31) +/** Sources the TV encoder input from pipe B instead of A. */ +# define TV_ENC_PIPEB_SELECT (1 << 30) +/** Outputs composite video (DAC A only) */ +# define TV_ENC_OUTPUT_COMPOSITE (0 << 28) +/** Outputs SVideo video (DAC B/C) */ +# define TV_ENC_OUTPUT_SVIDEO (1 << 28) +/** Outputs Component video (DAC A/B/C) */ +# define TV_ENC_OUTPUT_COMPONENT (2 << 28) +/** Outputs Composite and SVideo (DAC A/B/C) */ +# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE (3 << 28) +# define TV_TRILEVEL_SYNC (1 << 21) +/** Enables slow sync generation (945GM only) */ +# define TV_SLOW_SYNC (1 << 20) +/** Selects 4x oversampling for 480i and 576p */ +# define TV_OVERSAMPLE_4X (0 << 18) +/** Selects 2x oversampling for 720p and 1080i */ +# define TV_OVERSAMPLE_2X (1 << 18) +/** Selects no oversampling for 1080p */ +# define TV_OVERSAMPLE_NONE (2 << 18) +/** Selects 8x oversampling */ +# define TV_OVERSAMPLE_8X (3 << 18) +/** Selects progressive mode rather than interlaced */ +# define TV_PROGRESSIVE (1 << 17) +/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */ +# define TV_PAL_BURST (1 << 16) +/** Field for setting delay of Y compared to C */ +# define TV_YC_SKEW_MASK (7 << 12) +/** Enables a fix for 480p/576p standard definition modes on the 915GM only */ +# define TV_ENC_SDP_FIX (1 << 11) /** - * The i830 generation, in LVDS mode, defines P1 as the bit number set within - * this field (only one bit may be set). + * Enables a fix for the 915GM only. + * + * Not sure what it does. */ -# define DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS 0x003f0000 -# define DPLL_FPA01_P1_POST_DIV_SHIFT 16 -# define PLL_P2_DIVIDE_BY_4 (1 << 23) /* i830, required in DVO non-gang */ -# define PLL_P1_DIVIDE_BY_TWO (1 << 21) /* i830 */ -# define PLL_REF_INPUT_DREFCLK (0 << 13) -# define PLL_REF_INPUT_TVCLKINA (1 << 13) /* i830 */ -# define PLL_REF_INPUT_TVCLKINBC (2 << 13) /* SDVO TVCLKIN */ -# define PLLB_REF_INPUT_SPREADSPECTRUMIN (3 << 13) -# define PLL_REF_INPUT_MASK (3 << 13) -# define PLL_LOAD_PULSE_PHASE_SHIFT 9 -/* - * Parallel to Serial Load Pulse phase selection. - * Selects the phase for the 10X DPLL clock for the PCIe - * digital display port. The range is 4 to 13; 10 or more - * is just a flip delay. The default is 6 +# define TV_ENC_C0_FIX (1 << 10) +/** Bits that must be preserved by software */ +# define TV_CTL_SAVE ((3 << 8) | (3 << 6)) +# define TV_FUSE_STATE_MASK (3 << 4) +/** Read-only state that reports all features enabled */ +# define TV_FUSE_STATE_ENABLED (0 << 4) +/** Read-only state that reports that Macrovision is disabled in hardware*/ +# define TV_FUSE_STATE_NO_MACROVISION (1 << 4) +/** Read-only state that reports that TV-out is disabled in hardware. */ +# define TV_FUSE_STATE_DISABLED (2 << 4) +/** Normal operation */ +# define TV_TEST_MODE_NORMAL (0 << 0) +/** Encoder test pattern 1 - combo pattern */ +# define TV_TEST_MODE_PATTERN_1 (1 << 0) +/** Encoder test pattern 2 - full screen vertical 75% color bars */ +# define TV_TEST_MODE_PATTERN_2 (2 << 0) +/** Encoder test pattern 3 - full screen horizontal 75% color bars */ +# define TV_TEST_MODE_PATTERN_3 (3 << 0) +/** Encoder test pattern 4 - random noise */ +# define TV_TEST_MODE_PATTERN_4 (4 << 0) +/** Encoder test pattern 5 - linear color ramps */ +# define TV_TEST_MODE_PATTERN_5 (5 << 0) +/** + * This test mode forces the DACs to 50% of full output. + * + * This is used for load detection in combination with TVDAC_SENSE_MASK */ -# define PLL_LOAD_PULSE_PHASE_MASK (0xf << PLL_LOAD_PULSE_PHASE_SHIFT) -# define DISPLAY_RATE_SELECT_FPA1 (1 << 8) +# define TV_TEST_MODE_MONITOR_DETECT (7 << 0) +# define TV_TEST_MODE_MASK (7 << 0) +#define TV_DAC 0x68004 /** - * SDVO multiplier for 945G/GM. Not used on 965. + * Reports that DAC state change logic has reported change (RO). * - * \sa DPLL_MD_UDI_MULTIPLIER_MASK + * This gets cleared when TV_DAC_STATE_EN is cleared +*/ +# define TVDAC_STATE_CHG (1 << 31) +# define TVDAC_SENSE_MASK (7 << 28) +/** Reports that DAC A voltage is above the detect threshold */ +# define TVDAC_A_SENSE (1 << 30) +/** Reports that DAC B voltage is above the detect threshold */ +# define TVDAC_B_SENSE (1 << 29) +/** Reports that DAC C voltage is above the detect threshold */ +# define TVDAC_C_SENSE (1 << 28) +/** + * Enables DAC state detection logic, for load-based TV detection. + * + * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set + * to off, for load detection to work. */ -# define SDVO_MULTIPLIER_MASK 0x000000ff -# define SDVO_MULTIPLIER_SHIFT_HIRES 4 -# define SDVO_MULTIPLIER_SHIFT_VGA 0 +# define TVDAC_STATE_CHG_EN (1 << 27) +/** Sets the DAC A sense value to high */ +# define TVDAC_A_SENSE_CTL (1 << 26) +/** Sets the DAC B sense value to high */ +# define TVDAC_B_SENSE_CTL (1 << 25) +/** Sets the DAC C sense value to high */ +# define TVDAC_C_SENSE_CTL (1 << 24) +/** Overrides the ENC_ENABLE and DAC voltage levels */ +# define DAC_CTL_OVERRIDE (1 << 7) +/** Sets the slew rate. Must be preserved in software */ +# define ENC_TVDAC_SLEW_FAST (1 << 6) +# define DAC_A_1_3_V (0 << 4) +# define DAC_A_1_1_V (1 << 4) +# define DAC_A_0_7_V (2 << 4) +# define DAC_A_OFF (3 << 4) +# define DAC_B_1_3_V (0 << 2) +# define DAC_B_1_1_V (1 << 2) +# define DAC_B_0_7_V (2 << 2) +# define DAC_B_OFF (3 << 2) +# define DAC_C_1_3_V (0 << 0) +# define DAC_C_1_1_V (1 << 0) +# define DAC_C_0_7_V (2 << 0) +# define DAC_C_OFF (3 << 0) -/** @defgroup DPLL_MD - * @{ +/** + * CSC coefficients are stored in a floating point format with 9 bits of + * mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n, + * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with + * -1 (0x3) being the only legal negative value. */ -/** Pipe A SDVO/UDI clock multiplier/divider register for G965. */ -#define DPLL_A_MD 0x0601c -/** Pipe B SDVO/UDI clock multiplier/divider register for G965. */ -#define DPLL_B_MD 0x06020 +#define TV_CSC_Y 0x68010 +# define TV_RY_MASK 0x07ff0000 +# define TV_RY_SHIFT 16 +# define TV_GY_MASK 0x00000fff +# define TV_GY_SHIFT 0 + +#define TV_CSC_Y2 0x68014 +# define TV_BY_MASK 0x07ff0000 +# define TV_BY_SHIFT 16 /** - * UDI pixel divider, controlling how many pixels are stuffed into a packet. + * Y attenuation for component video. * - * Value is pixels minus 1. Must be set to 1 pixel for SDVO. + * Stored in 1.9 fixed point. */ -# define DPLL_MD_UDI_DIVIDER_MASK 0x3f000000 -# define DPLL_MD_UDI_DIVIDER_SHIFT 24 -/** UDI pixel divider for VGA, same as DPLL_MD_UDI_DIVIDER_MASK. */ -# define DPLL_MD_VGA_UDI_DIVIDER_MASK 0x003f0000 -# define DPLL_MD_VGA_UDI_DIVIDER_SHIFT 16 +# define TV_AY_MASK 0x000003ff +# define TV_AY_SHIFT 0 + +#define TV_CSC_U 0x68018 +# define TV_RU_MASK 0x07ff0000 +# define TV_RU_SHIFT 16 +# define TV_GU_MASK 0x000007ff +# define TV_GU_SHIFT 0 + +#define TV_CSC_U2 0x6801c +# define TV_BU_MASK 0x07ff0000 +# define TV_BU_SHIFT 16 /** - * SDVO/UDI pixel multiplier. - * - * SDVO requires that the bus clock rate be between 1 and 2 Ghz, and the bus - * clock rate is 10 times the DPLL clock. At low resolution/refresh rate - * modes, the bus rate would be below the limits, so SDVO allows for stuffing - * dummy bytes in the datastream at an increased clock rate, with both sides of - * the link knowing how many bytes are fill. + * U attenuation for component video. * - * So, for a mode with a dotclock of 65Mhz, we would want to double the clock - * rate to 130Mhz to get a bus rate of 1.30Ghz. The DPLL clock rate would be - * set to 130Mhz, and the SDVO multiplier set to 2x in this register and - * through an SDVO command. + * Stored in 1.9 fixed point. + */ +# define TV_AU_MASK 0x000003ff +# define TV_AU_SHIFT 0 + +#define TV_CSC_V 0x68020 +# define TV_RV_MASK 0x0fff0000 +# define TV_RV_SHIFT 16 +# define TV_GV_MASK 0x000007ff +# define TV_GV_SHIFT 0 + +#define TV_CSC_V2 0x68024 +# define TV_BV_MASK 0x07ff0000 +# define TV_BV_SHIFT 16 +/** + * V attenuation for component video. * - * This register field has values of multiplication factor minus 1, with - * a maximum multiplier of 5 for SDVO. + * Stored in 1.9 fixed point. */ -# define DPLL_MD_UDI_MULTIPLIER_MASK 0x00003f00 -# define DPLL_MD_UDI_MULTIPLIER_SHIFT 8 -/** SDVO/UDI pixel multiplier for VGA, same as DPLL_MD_UDI_MULTIPLIER_MASK. - * This best be set to the default value (3) or the CRT won't work. No, - * I don't entirely understand what this does... +# define TV_AV_MASK 0x000007ff +# define TV_AV_SHIFT 0 + +#define TV_CLR_KNOBS 0x68028 +/** 2s-complement brightness adjustment */ +# define TV_BRIGHTNESS_MASK 0xff000000 +# define TV_BRIGHTNESS_SHIFT 24 +/** Contrast adjustment, as a 2.6 unsigned floating point number */ +# define TV_CONTRAST_MASK 0x00ff0000 +# define TV_CONTRAST_SHIFT 16 +/** Saturation adjustment, as a 2.6 unsigned floating point number */ +# define TV_SATURATION_MASK 0x0000ff00 +# define TV_SATURATION_SHIFT 8 +/** Hue adjustment, as an integer phase angle in degrees */ +# define TV_HUE_MASK 0x000000ff +# define TV_HUE_SHIFT 0 + +#define TV_CLR_LEVEL 0x6802c +/** Controls the DAC level for black */ +# define TV_BLACK_LEVEL_MASK 0x01ff0000 +# define TV_BLACK_LEVEL_SHIFT 16 +/** Controls the DAC level for blanking */ +# define TV_BLANK_LEVEL_MASK 0x000001ff +# define TV_BLANK_LEVEL_SHIFT 0 + +#define TV_H_CTL_1 0x68030 +/** Number of pixels in the hsync. */ +# define TV_HSYNC_END_MASK 0x1fff0000 +# define TV_HSYNC_END_SHIFT 16 +/** Total number of pixels minus one in the line (display and blanking). */ +# define TV_HTOTAL_MASK 0x00001fff +# define TV_HTOTAL_SHIFT 0 + +#define TV_H_CTL_2 0x68034 +/** Enables the colorburst (needed for non-component color) */ +# define TV_BURST_ENA (1 << 31) +/** Offset of the colorburst from the start of hsync, in pixels minus one. */ +# define TV_HBURST_START_SHIFT 16 +# define TV_HBURST_START_MASK 0x1fff0000 +/** Length of the colorburst */ +# define TV_HBURST_LEN_SHIFT 0 +# define TV_HBURST_LEN_MASK 0x0001fff + +#define TV_H_CTL_3 0x68038 +/** End of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_END_SHIFT 16 +# define TV_HBLANK_END_MASK 0x1fff0000 +/** Start of hblank, measured in pixels minus one from start of hsync */ +# define TV_HBLANK_START_SHIFT 0 +# define TV_HBLANK_START_MASK 0x0001fff + +#define TV_V_CTL_1 0x6803c +/** XXX */ +# define TV_NBR_END_SHIFT 16 +# define TV_NBR_END_MASK 0x07ff0000 +/** XXX */ +# define TV_VI_END_F1_SHIFT 8 +# define TV_VI_END_F1_MASK 0x00003f00 +/** XXX */ +# define TV_VI_END_F2_SHIFT 0 +# define TV_VI_END_F2_MASK 0x0000003f + +#define TV_V_CTL_2 0x68040 +/** Length of vsync, in half lines */ +# define TV_VSYNC_LEN_MASK 0x07ff0000 +# define TV_VSYNC_LEN_SHIFT 16 +/** Offset of the start of vsync in field 1, measured in one less than the + * number of half lines. */ -# define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f -# define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -/** @} */ - -#define DPLL_TEST 0x606c -# define DPLLB_TEST_SDVO_DIV_1 (0 << 22) -# define DPLLB_TEST_SDVO_DIV_2 (1 << 22) -# define DPLLB_TEST_SDVO_DIV_4 (2 << 22) -# define DPLLB_TEST_SDVO_DIV_MASK (3 << 22) -# define DPLLB_TEST_N_BYPASS (1 << 19) -# define DPLLB_TEST_M_BYPASS (1 << 18) -# define DPLLB_INPUT_BUFFER_ENABLE (1 << 16) -# define DPLLA_TEST_N_BYPASS (1 << 3) -# define DPLLA_TEST_M_BYPASS (1 << 2) -# define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) - -#define ADPA 0x61100 -#define ADPA_DAC_ENABLE (1<<31) -#define ADPA_DAC_DISABLE 0 -#define ADPA_PIPE_SELECT_MASK (1<<30) -#define ADPA_PIPE_A_SELECT 0 -#define ADPA_PIPE_B_SELECT (1<<30) -#define ADPA_USE_VGA_HVPOLARITY (1<<15) -#define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<11) -#define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<10) -#define ADPA_HSYNC_CNTL_ENABLE 0 -#define ADPA_VSYNC_ACTIVE_HIGH (1<<4) -#define ADPA_VSYNC_ACTIVE_LOW 0 -#define ADPA_HSYNC_ACTIVE_HIGH (1<<3) -#define ADPA_HSYNC_ACTIVE_LOW 0 - -#define FPA0 0x06040 -#define FPA1 0x06044 -#define FPB0 0x06048 -#define FPB1 0x0604c -# define FP_N_DIV_MASK 0x003f0000 -# define FP_N_DIV_SHIFT 16 -# define FP_M1_DIV_MASK 0x00003f00 -# define FP_M1_DIV_SHIFT 8 -# define FP_M2_DIV_MASK 0x0000003f -# define FP_M2_DIV_SHIFT 0 +# define TV_VSYNC_START_F1_MASK 0x00007f00 +# define TV_VSYNC_START_F1_SHIFT 8 +/** + * Offset of the start of vsync in field 2, measured in one less than the + * number of half lines. + */ +# define TV_VSYNC_START_F2_MASK 0x0000007f +# define TV_VSYNC_START_F2_SHIFT 0 + +#define TV_V_CTL_3 0x68044 +/** Enables generation of the equalization signal */ +# define TV_EQUAL_ENA (1 << 31) +/** Length of vsync, in half lines */ +# define TV_VEQ_LEN_MASK 0x007f0000 +# define TV_VEQ_LEN_SHIFT 16 +/** Offset of the start of equalization in field 1, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F1_MASK 0x0007f00 +# define TV_VEQ_START_F1_SHIFT 8 +/** + * Offset of the start of equalization in field 2, measured in one less than + * the number of half lines. + */ +# define TV_VEQ_START_F2_MASK 0x000007f +# define TV_VEQ_START_F2_SHIFT 0 +#define TV_V_CTL_4 0x68048 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F1_MASK 0x003f0000 +# define TV_VBURST_START_F1_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F1_MASK 0x000000ff +# define TV_VBURST_END_F1_SHIFT 0 -#define PORT_HOTPLUG_EN 0x61110 -# define SDVOB_HOTPLUG_INT_EN (1 << 26) -# define SDVOC_HOTPLUG_INT_EN (1 << 25) -# define TV_HOTPLUG_INT_EN (1 << 18) -# define CRT_HOTPLUG_INT_EN (1 << 9) -# define CRT_HOTPLUG_FORCE_DETECT (1 << 3) +#define TV_V_CTL_5 0x6804c +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F2_MASK 0x003f0000 +# define TV_VBURST_START_F2_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F2_MASK 0x000000ff +# define TV_VBURST_END_F2_SHIFT 0 -#define PORT_HOTPLUG_STAT 0x61114 -# define CRT_HOTPLUG_INT_STATUS (1 << 11) -# define TV_HOTPLUG_INT_STATUS (1 << 10) -# define CRT_HOTPLUG_MONITOR_MASK (3 << 8) -# define CRT_HOTPLUG_MONITOR_COLOR (3 << 8) -# define CRT_HOTPLUG_MONITOR_MONO (2 << 8) -# define CRT_HOTPLUG_MONITOR_NONE (0 << 8) -# define SDVOC_HOTPLUG_INT_STATUS (1 << 7) -# define SDVOB_HOTPLUG_INT_STATUS (1 << 6) +#define TV_V_CTL_6 0x68050 +/** + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F3_MASK 0x003f0000 +# define TV_VBURST_START_F3_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F3_MASK 0x000000ff +# define TV_VBURST_END_F3_SHIFT 0 -#define SDVOB 0x61140 -#define SDVOC 0x61160 -#define SDVO_ENABLE (1 << 31) -#define SDVO_PIPE_B_SELECT (1 << 30) -#define SDVO_STALL_SELECT (1 << 29) -#define SDVO_INTERRUPT_ENABLE (1 << 26) +#define TV_V_CTL_7 0x68054 /** - * 915G/GM SDVO pixel multiplier. - * - * Programmed value is multiplier - 1, up to 5x. + * Offset to start of vertical colorburst, measured in one less than the + * number of lines from vertical start. + */ +# define TV_VBURST_START_F4_MASK 0x003f0000 +# define TV_VBURST_START_F4_SHIFT 16 +/** + * Offset to the end of vertical colorburst, measured in one less than the + * number of lines from the start of NBR. + */ +# define TV_VBURST_END_F4_MASK 0x000000ff +# define TV_VBURST_END_F4_SHIFT 0 + +#define TV_SC_CTL_1 0x68060 +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA1_EN (1 << 31) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA2_EN (1 << 30) +/** Turns on the first subcarrier phase generation DDA */ +# define TV_SC_DDA3_EN (1 << 29) +/** Sets the subcarrier DDA to reset frequency every other field */ +# define TV_SC_RESET_EVERY_2 (0 << 24) +/** Sets the subcarrier DDA to reset frequency every fourth field */ +# define TV_SC_RESET_EVERY_4 (1 << 24) +/** Sets the subcarrier DDA to reset frequency every eighth field */ +# define TV_SC_RESET_EVERY_8 (2 << 24) +/** Sets the subcarrier DDA to never reset the frequency */ +# define TV_SC_RESET_NEVER (3 << 24) +/** Sets the peak amplitude of the colorburst.*/ +# define TV_BURST_LEVEL_MASK 0x00ff0000 +# define TV_BURST_LEVEL_SHIFT 16 +/** Sets the increment of the first subcarrier phase generation DDA */ +# define TV_SCDDA1_INC_MASK 0x00000fff +# define TV_SCDDA1_INC_SHIFT 0 + +#define TV_SC_CTL_2 0x68064 +/** Sets the rollover for the second subcarrier phase generation DDA */ +# define TV_SCDDA2_SIZE_MASK 0x7fff0000 +# define TV_SCDDA2_SIZE_SHIFT 16 +/** Sets the increent of the second subcarrier phase generation DDA */ +# define TV_SCDDA2_INC_MASK 0x00007fff +# define TV_SCDDA2_INC_SHIFT 0 + +#define TV_SC_CTL_3 0x68068 +/** Sets the rollover for the third subcarrier phase generation DDA */ +# define TV_SCDDA3_SIZE_MASK 0x7fff0000 +# define TV_SCDDA3_SIZE_SHIFT 16 +/** Sets the increent of the third subcarrier phase generation DDA */ +# define TV_SCDDA3_INC_MASK 0x00007fff +# define TV_SCDDA3_INC_SHIFT 0 + +#define TV_WIN_POS 0x68070 +/** X coordinate of the display from the start of horizontal active */ +# define TV_XPOS_MASK 0x1fff0000 +# define TV_XPOS_SHIFT 16 +/** Y coordinate of the display from the start of vertical active (NBR) */ +# define TV_YPOS_MASK 0x00000fff +# define TV_YPOS_SHIFT 0 + +#define TV_WIN_SIZE 0x68074 +/** Horizontal size of the display window, measured in pixels*/ +# define TV_XSIZE_MASK 0x1fff0000 +# define TV_XSIZE_SHIFT 16 +/** + * Vertical size of the display window, measured in pixels. * - * \sa DPLL_MD_UDI_MULTIPLIER_MASK + * Must be even for interlaced modes. */ -#define SDVO_PORT_MULTIPLY_MASK (7 << 23) -#define SDVO_PORT_MULTIPLY_SHIFT 23 -#define SDVO_PHASE_SELECT_MASK (15 << 19) -#define SDVO_PHASE_SELECT_DEFAULT (6 << 19) -#define SDVO_CLOCK_OUTPUT_INVERT (1 << 18) -#define SDVOC_GANG_MODE (1 << 16) -#define SDVO_BORDER_ENABLE (1 << 7) -#define SDVOB_PCIE_CONCURRENCY (1 << 3) -#define SDVO_DETECTED (1 << 2) -/* Bits to be preserved when writing */ -#define SDVOB_PRESERVE_MASK ((1 << 17) | (1 << 16) | (1 << 14)) -#define SDVOC_PRESERVE_MASK (1 << 17) +# define TV_YSIZE_MASK 0x00000fff +# define TV_YSIZE_SHIFT 0 -/** @defgroup LVDS - * @{ - */ +#define TV_FILTER_CTL_1 0x68080 /** - * This register controls the LVDS output enable, pipe selection, and data - * format selection. + * Enables automatic scaling calculation. * - * All of the clock/data pairs are force powered down by power sequencing. + * If set, the rest of the registers are ignored, and the calculated values can + * be read back from the register. */ -#define LVDS 0x61180 +# define TV_AUTO_SCALE (1 << 31) /** - * Enables the LVDS port. This bit must be set before DPLLs are enabled, as - * the DPLL semantics change when the LVDS is assigned to that pipe. + * Disables the vertical filter. + * + * This is required on modes more than 1024 pixels wide */ +# define TV_V_FILTER_BYPASS (1 << 29) +/** Enables adaptive vertical filtering */ +# define TV_VADAPT (1 << 28) +# define TV_VADAPT_MODE_MASK (3 << 26) +/** Selects the least adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_LEAST (0 << 26) +/** Selects the moderately adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MODERATE (1 << 26) +/** Selects the most adaptive vertical filtering mode */ +# define TV_VADAPT_MODE_MOST (3 << 26) +/** + * Sets the horizontal scaling factor. + * + * This should be the fractional part of the horizontal scaling factor divided + * by the oversampling rate. TV_HSCALE should be less than 1, and set to: + * + * (src width - 1) / ((oversample * dest width) - 1) */ -# 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 TV_HSCALE_FRAC_MASK 0x00003fff +# define TV_HSCALE_FRAC_SHIFT 0 +#define TV_FILTER_CTL_2 0x68084 /** - * Enables the A0-A2 data pairs and CLKA, containing 18 bits of color data per - * pixel. + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1) */ -# define LVDS_A0A2_CLKA_POWER_MASK (3 << 8) -# define LVDS_A0A2_CLKA_POWER_DOWN (0 << 8) -# define LVDS_A0A2_CLKA_POWER_UP (3 << 8) +# define TV_VSCALE_INT_MASK 0x00038000 +# define TV_VSCALE_INT_SHIFT 15 /** - * Controls the A3 data pair, which contains the additional LSBs for 24 bit - * mode. Only enabled if LVDS_A0A2_CLKA_POWER_UP also indicates it should be - * on. + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * \sa TV_VSCALE_INT_MASK */ -# define LVDS_A3_POWER_MASK (3 << 6) -# define LVDS_A3_POWER_DOWN (0 << 6) -# define LVDS_A3_POWER_UP (3 << 6) +# define TV_VSCALE_FRAC_MASK 0x00007fff +# define TV_VSCALE_FRAC_SHIFT 0 + +#define TV_FILTER_CTL_3 0x68088 /** - * Controls the CLKB pair. This should only be set when LVDS_B0B3_POWER_UP - * is set. + * Sets the integer part of the 3.15 fixed-point vertical scaling factor. + * + * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1)) + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. */ -# define LVDS_CLKB_POWER_MASK (3 << 4) -# define LVDS_CLKB_POWER_DOWN (0 << 4) -# define LVDS_CLKB_POWER_UP (3 << 4) +# define TV_VSCALE_IP_INT_MASK 0x00038000 +# define TV_VSCALE_IP_INT_SHIFT 15 +/** + * Sets the fractional part of the 3.15 fixed-point vertical scaling factor. + * + * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes. + * + * \sa TV_VSCALE_IP_INT_MASK + */ +# define TV_VSCALE_IP_FRAC_MASK 0x00007fff +# define TV_VSCALE_IP_FRAC_SHIFT 0 +#define TV_CC_CONTROL 0x68090 +# define TV_CC_ENABLE (1 << 31) /** - * Controls the B0-B3 data pairs. This must be set to match the DPLL p2 - * setting for whether we are in dual-channel mode. The B3 pair will - * additionally only be powered up when LVDS_A3_POWER_UP is set. + * Specifies which field to send the CC data in. + * + * CC data is usually sent in field 0. + */ +# define TV_CC_FID_MASK (1 << 27) +# define TV_CC_FID_SHIFT 27 +/** Sets the horizontal position of the CC data. Usually 135. */ +# define TV_CC_HOFF_MASK 0x03ff0000 +# define TV_CC_HOFF_SHIFT 16 +/** Sets the vertical position of the CC data. Usually 21 */ +# define TV_CC_LINE_MASK 0x0000003f +# define TV_CC_LINE_SHIFT 0 + +#define TV_CC_DATA 0x68094 +# define TV_CC_RDY (1 << 31) +/** Second word of CC data to be transmitted. */ +# define TV_CC_DATA_2_MASK 0x007f0000 +# define TV_CC_DATA_2_SHIFT 16 +/** First word of CC data to be transmitted. */ +# define TV_CC_DATA_1_MASK 0x0000007f +# define TV_CC_DATA_1_SHIFT 0 + +#define TV_H_LUMA_0 0x68100 +#define TV_H_LUMA_59 0x681ec +#define TV_H_CHROMA_0 0x68200 +#define TV_H_CHROMA_59 0x682ec +#define TV_V_LUMA_0 0x68300 +#define TV_V_LUMA_42 0x683a8 +#define TV_V_CHROMA_0 0x68400 +#define TV_V_CHROMA_42 0x684a8 + +/* Display & cursor control */ + +/* Pipe A */ +#define PIPEADSL 0x70000 +#define PIPEACONF 0x70008 +#define PIPEACONF_ENABLE (1<<31) +#define PIPEACONF_DISABLE 0 +#define PIPEACONF_DOUBLE_WIDE (1<<30) +#define I965_PIPECONF_ACTIVE (1<<30) +#define PIPEACONF_SINGLE_WIDE 0 +#define PIPEACONF_PIPE_UNLOCKED 0 +#define PIPEACONF_PIPE_LOCKED (1<<25) +#define PIPEACONF_PALETTE 0 +#define PIPEACONF_GAMMA (1<<24) +#define PIPECONF_FORCE_BORDER (1<<25) +#define PIPECONF_PROGRESSIVE (0 << 21) +#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) +#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) +#define PIPEASTAT 0x70024 +#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) +#define PIPE_CRC_ERROR_ENABLE (1UL<<29) +#define PIPE_CRC_DONE_ENABLE (1UL<<28) +#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27) +#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26) +#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) +#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) +#define PIPE_DPST_EVENT_ENABLE (1UL<<23) +#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) +#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) +#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) +#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17) +#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) +#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) +#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) +#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) +#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10) +#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9) +#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) +#define PIPE_DPST_EVENT_STATUS (1UL<<7) +#define PIPE_LEGACY_BLC_EVENT_STATUS (1UL<<6) +#define PIPE_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) +#define PIPE_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) +#define PIPE_HOTPLUG_TV_INTERRUPT_STATUS (1UL<<2) /* pre-965 */ +#define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ +#define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) +#define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) + +#define DSPARB 0x70030 +#define DSPARB_CSTART_MASK (0x7f << 7) +#define DSPARB_CSTART_SHIFT 7 +#define DSPARB_BSTART_MASK (0x7f) +#define DSPARB_BSTART_SHIFT 0 +/* + * The two pipe frame counter registers are not synchronized, so + * reading a stable value is somewhat tricky. The following code + * should work: + * + * do { + * high1 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT; + * low1 = ((INREG(PIPEAFRAMEPIXEL) & PIPE_FRAME_LOW_MASK) >> + * PIPE_FRAME_LOW_SHIFT); + * high2 = ((INREG(PIPEAFRAMEHIGH) & PIPE_FRAME_HIGH_MASK) >> + * PIPE_FRAME_HIGH_SHIFT); + * } while (high1 != high2); + * frame = (high1 << 8) | low1; */ -# define LVDS_B0B3_POWER_MASK (3 << 2) -# define LVDS_B0B3_POWER_DOWN (0 << 2) -# define LVDS_B0B3_POWER_UP (3 << 2) - -#define PIPEACONF 0x70008 -#define PIPEACONF_ENABLE (1<<31) -#define PIPEACONF_DISABLE 0 -#define PIPEACONF_DOUBLE_WIDE (1<<30) -#define I965_PIPECONF_ACTIVE (1<<30) -#define PIPEACONF_SINGLE_WIDE 0 -#define PIPEACONF_PIPE_UNLOCKED 0 -#define PIPEACONF_PIPE_LOCKED (1<<25) -#define PIPEACONF_PALETTE 0 -#define PIPEACONF_GAMMA (1<<24) -#define PIPECONF_FORCE_BORDER (1<<25) -#define PIPECONF_PROGRESSIVE (0 << 21) -#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21) -#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21) - -#define DSPARB 0x70030 -#define DSPARB_CSTART_MASK (0x7f << 7) -#define DSPARB_CSTART_SHIFT 7 -#define DSPARB_BSTART_MASK (0x7f) -#define DSPARB_BSTART_SHIFT 0 - -#define PIPEBCONF 0x71008 -#define PIPEBCONF_ENABLE (1<<31) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_DOUBLE_WIDE (1<<30) -#define PIPEBCONF_DISABLE 0 -#define PIPEBCONF_GAMMA (1<<24) -#define PIPEBCONF_PALETTE 0 - -#define PIPEBGCMAXRED 0x71010 -#define PIPEBGCMAXGREEN 0x71014 -#define PIPEBGCMAXBLUE 0x71018 +#define PIPEAFRAMEHIGH 0x70040 +#define PIPE_FRAME_HIGH_MASK 0x0000ffff +#define PIPE_FRAME_HIGH_SHIFT 0 +#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 + +/* Cursor A & B regs */ +#define CURACNTR 0x70080 +#define CURSOR_MODE_DISABLE 0x00 +#define CURSOR_MODE_64_32B_AX 0x07 +#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) +#define MCURSOR_GAMMA_ENABLE (1 << 26) +#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 CURBCNTR 0x700c0 +#define CURBBASE 0x700c4 +#define CURBPOS 0x700c8 + +/* Display A control */ +#define DSPACNTR 0x70180 +#define DISPLAY_PLANE_ENABLE (1<<31) +#define DISPLAY_PLANE_DISABLE 0 +#define DISPPLANE_GAMMA_ENABLE (1<<30) +#define DISPPLANE_GAMMA_DISABLE 0 +#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) +#define DISPPLANE_8BPP (0x2<<26) +#define DISPPLANE_15_16BPP (0x4<<26) +#define DISPPLANE_16BPP (0x5<<26) +#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) +#define DISPPLANE_32BPP (0x7<<26) +#define DISPPLANE_STEREO_ENABLE (1<<25) +#define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_SEL_PIPE_MASK (1<<24) +#define DISPPLANE_SEL_PIPE_A 0 +#define DISPPLANE_SEL_PIPE_B (1<<24) +#define DISPPLANE_SRC_KEY_ENABLE (1<<22) +#define DISPPLANE_SRC_KEY_DISABLE 0 +#define DISPPLANE_LINE_DOUBLE (1<<20) +#define DISPPLANE_NO_LINE_DOUBLE 0 +#define DISPPLANE_STEREO_POLARITY_FIRST 0 +#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) +#define DSPAADDR 0x70184 +#define DSPASTRIDE 0x70188 +#define DSPAPOS 0x7018C /* reserved */ +#define DSPASIZE 0x70190 +#define DSPASURF 0x7019C /* 965+ only */ +#define DSPATILEOFF 0x701A4 /* 965+ only */ + +/* VBIOS flags */ +#define SWF00 0x71410 +#define SWF01 0x71414 +#define SWF02 0x71418 +#define SWF03 0x7141c +#define SWF04 0x71420 +#define SWF05 0x71424 +#define SWF06 0x71428 +#define SWF10 0x70410 +#define SWF11 0x70414 +#define SWF14 0x71420 +#define SWF30 0x72414 +#define SWF31 0x72418 +#define SWF32 0x7241c + +/* Pipe B */ +#define PIPEBDSL 0x71000 +#define PIPEBCONF 0x71008 #define PIPEBSTAT 0x71024 #define PIPEBFRAMEHIGH 0x71040 #define PIPEBFRAMEPIXEL 0x71044 -#define DSPACNTR 0x70180 +/* Display B control */ #define DSPBCNTR 0x71180 -#define DISPLAY_PLANE_ENABLE (1<<31) -#define DISPLAY_PLANE_DISABLE 0 -#define DISPPLANE_GAMMA_ENABLE (1<<30) -#define DISPPLANE_GAMMA_DISABLE 0 -#define DISPPLANE_PIXFORMAT_MASK (0xf<<26) -#define DISPPLANE_8BPP (0x2<<26) -#define DISPPLANE_15_16BPP (0x4<<26) -#define DISPPLANE_16BPP (0x5<<26) -#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26) -#define DISPPLANE_32BPP (0x7<<26) -#define DISPPLANE_STEREO_ENABLE (1<<25) -#define DISPPLANE_STEREO_DISABLE 0 -#define DISPPLANE_SEL_PIPE_MASK (1<<24) -#define DISPPLANE_SEL_PIPE_A 0 -#define DISPPLANE_SEL_PIPE_B (1<<24) -#define DISPPLANE_SRC_KEY_ENABLE (1<<22) -#define DISPPLANE_SRC_KEY_DISABLE 0 -#define DISPPLANE_LINE_DOUBLE (1<<20) -#define DISPPLANE_NO_LINE_DOUBLE 0 -#define DISPPLANE_STEREO_POLARITY_FIRST 0 -#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18) -/* plane B only */ -#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) -#define DISPPLANE_ALPHA_TRANS_DISABLE 0 -#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0 -#define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) - -#define DSPABASE 0x70184 -#define DSPASTRIDE 0x70188 - -#define DSPBBASE 0x71184 -#define DSPBADDR DSPBBASE +#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 DSPAKEYVAL 0x70194 -#define DSPAKEYMASK 0x70198 - -#define DSPAPOS 0x7018C /* reserved */ -#define DSPASIZE 0x70190 #define DSPBPOS 0x7118C #define DSPBSIZE 0x71190 - -#define DSPASURF 0x7019C -#define DSPATILEOFF 0x701A4 - #define DSPBSURF 0x7119C #define DSPBTILEOFF 0x711A4 +/* VBIOS regs */ #define VGACNTRL 0x71400 # define VGA_DISP_DISABLE (1 << 31) # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) -/* - * Some BIOS scratch area registers. The 845 (and 830?) store the amount - * of video memory available to the BIOS in SWF1. - */ - -#define SWF0 0x71410 - -/* - * 855 scratch registers. - */ -#define SWF10 0x70410 - -#define SWF30 0x72414 - -/* - * Overlay registers. These are overlay registers accessed via MMIO. - * Those loaded via the overlay register page are defined in i830_video.c. - */ -#define OVADD 0x30000 - -#define DOVSTA 0x30008 -#define OC_BUF (0x3<<20) - -#define OGAMC5 0x30010 -#define OGAMC4 0x30014 -#define OGAMC3 0x30018 -#define OGAMC2 0x3001c -#define OGAMC1 0x30020 -#define OGAMC0 0x30024 -/* - * Palette registers - */ -#define PALETTE_A 0x0a000 -#define PALETTE_B 0x0a800 +/* Chipset type macros */ #define IS_I830(dev) ((dev)->pci_device == 0x3577) #define IS_845G(dev) ((dev)->pci_device == 0x2562) @@ -1318,6 +1819,4 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev)) -#define PRIMARY_RINGBUFFER_SIZE (128*1024) - #endif diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2287cd0c..0bf01bdd 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -443,17 +443,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u32 pipea_stats, pipeb_stats; int vblank = 0; - iir = I915_READ(I915REG_INT_IDENTITY_R); + iir = I915_READ(IIR); #if 0 DRM_DEBUG("flag=%08x\n", iir); #endif if (iir == 0) { DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", iir, - I915_READ(I915REG_INT_MASK_R), - I915_READ(I915REG_INT_ENABLE_R), - I915_READ(I915REG_PIPEASTAT), - I915_READ(I915REG_PIPEBSTAT)); + I915_READ(IMR), + I915_READ(IER), + I915_READ(PIPEASTAT), + I915_READ(PIPEBSTAT)); return IRQ_NONE; } @@ -462,31 +462,32 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) * we may get extra interrupts. */ if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { - pipea_stats = I915_READ(I915REG_PIPEASTAT); - if (pipea_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) + pipea_stats = I915_READ(PIPEASTAT); + if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 0)); } - I915_WRITE(I915REG_PIPEASTAT, pipea_stats); + + I915_WRITE(PIPEASTAT, pipea_stats); } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { - pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - if (pipeb_stats & (I915_START_VBLANK_INTERRUPT_STATUS| - I915_VBLANK_INTERRUPT_STATUS)) + pipeb_stats = I915_READ(PIPEBSTAT); + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) { vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 1)); } - I915_WRITE(I915REG_PIPEBSTAT, pipeb_stats); + I915_WRITE(PIPEBSTAT, pipeb_stats); } if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - I915_WRITE(I915REG_INT_IDENTITY_R, iir); - (void) I915_READ(I915REG_INT_IDENTITY_R); /* Flush posted write */ + I915_WRITE(IIR, iir); + (void) I915_READ(IIR); if (iir & I915_USER_INTERRUPT) { DRM_WAKEUP(&dev_priv->irq_queue); @@ -516,7 +517,7 @@ int i915_emit_irq(struct drm_device *dev) BEGIN_LP_RING(2); OUT_RING(0); - OUT_RING(GFX_OP_USER_INTERRUPT); + OUT_RING(MI_USER_INTERRUPT); ADVANCE_LP_RING(); return dev_priv->counter; @@ -527,7 +528,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); @@ -537,8 +538,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) { DRM_SPINLOCK(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - // I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; + // I915_WRITE(IER, dev_priv->irq_enable_reg); } DRM_SPINUNLOCK(&dev_priv->user_irq_lock); } @@ -622,11 +623,11 @@ int i915_enable_vblank(struct drm_device *dev, int plane) switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -643,17 +644,17 @@ int i915_enable_vblank(struct drm_device *dev, int plane) * but */ if (IS_I965G (dev)) - pipestat |= I915_START_VBLANK_INTERRUPT_ENABLE; + pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; else - pipestat |= I915_VBLANK_INTERRUPT_ENABLE; + pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; /* * Clear any pending status */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); } - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); return 0; } @@ -667,11 +668,11 @@ void i915_disable_vblank(struct drm_device *dev, int plane) switch (pipe) { case 0: - pipestat_reg = I915REG_PIPEASTAT; + pipestat_reg = PIPEASTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; break; case 1: - pipestat_reg = I915REG_PIPEBSTAT; + pipestat_reg = PIPEBSTAT; dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; break; default: @@ -680,17 +681,18 @@ void i915_disable_vblank(struct drm_device *dev, int plane) break; } - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); + if (pipestat_reg) { pipestat = I915_READ (pipestat_reg); - pipestat &= ~(I915_START_VBLANK_INTERRUPT_ENABLE | - I915_VBLANK_INTERRUPT_ENABLE); + pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | + PIPE_VBLANK_INTERRUPT_ENABLE); /* * Clear any pending status */ - pipestat |= (I915_START_VBLANK_INTERRUPT_STATUS | - I915_VBLANK_INTERRUPT_STATUS); + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); I915_WRITE(pipestat_reg, pipestat); } } @@ -701,7 +703,7 @@ static void i915_enable_interrupt (struct drm_device *dev) dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + I915_WRITE(IER, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; } @@ -740,7 +742,8 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, return -EINVAL; } - flag = I915_READ(I915REG_INT_ENABLE_R); + flag = I915_READ(IER); + pipe->pipe = 0; if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) pipe->pipe |= DRM_I915_VBLANK_PIPE_A; @@ -910,9 +913,9 @@ void i915_driver_irq_preinstall(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_HWSTAM, 0xeffe); - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + I915_WRITE16(HWSTAM, 0xeffe); + I915_WRITE16(IMR, 0x0); + I915_WRITE16(IER, 0x0); } int i915_driver_irq_postinstall(struct drm_device * dev) @@ -941,7 +944,7 @@ int i915_driver_irq_postinstall(struct drm_device * dev) * Initialize the hardware status page IRQ location. */ - I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); return 0; } @@ -954,14 +957,14 @@ void i915_driver_irq_uninstall(struct drm_device * dev) return; dev_priv->irq_enabled = 0; - I915_WRITE(I915REG_HWSTAM, 0xffffffff); - I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); - I915_WRITE(I915REG_INT_ENABLE_R, 0x0); - - temp = I915_READ(I915REG_PIPEASTAT); - I915_WRITE(I915REG_PIPEASTAT, temp); - temp = I915_READ(I915REG_PIPEBSTAT); - I915_WRITE(I915REG_PIPEBSTAT, temp); - temp = I915_READ(I915REG_INT_IDENTITY_R); - I915_WRITE(I915REG_INT_IDENTITY_R, temp); + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + + temp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, temp); + temp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, temp); + temp = I915_READ(IIR); + I915_WRITE(IIR, temp); } diff --git a/shared-core/i915_suspend.c b/shared-core/i915_suspend.c index d93bf6b3..63cd54a2 100644 --- a/shared-core/i915_suspend.c +++ b/shared-core/i915_suspend.c @@ -32,11 +32,6 @@ #include "i915_drm.h" #include "i915_drv.h" -enum pipe { - PIPE_A = 0, - PIPE_B, -}; - static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -275,13 +270,13 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveDSPASTRIDE = I915_READ(DSPASTRIDE); dev_priv->saveDSPASIZE = I915_READ(DSPASIZE); dev_priv->saveDSPAPOS = I915_READ(DSPAPOS); - dev_priv->saveDSPABASE = I915_READ(DSPABASE); + dev_priv->saveDSPAADDR = I915_READ(DSPAADDR); if (IS_I965G(dev)) { dev_priv->saveDSPASURF = I915_READ(DSPASURF); dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF); } i915_save_palette(dev, PIPE_A); - dev_priv->savePIPEASTAT = I915_READ(I915REG_PIPEASTAT); + dev_priv->savePIPEASTAT = I915_READ(PIPEASTAT); /* Pipe & plane B info */ dev_priv->savePIPEBCONF = I915_READ(PIPEBCONF); @@ -303,13 +298,13 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveDSPBSTRIDE = I915_READ(DSPBSTRIDE); dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); - dev_priv->saveDSPBBASE = I915_READ(DSPBBASE); + dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); if (IS_I965GM(dev) || IS_IGD_GM(dev)) { dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } i915_save_palette(dev, PIPE_B); - dev_priv->savePIPEBSTAT = I915_READ(I915REG_PIPEBSTAT); + dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); /* CRT state */ dev_priv->saveADPA = I915_READ(ADPA); @@ -324,9 +319,9 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveLVDS = I915_READ(LVDS); if (!IS_I830(dev) && !IS_845G(dev)) dev_priv->savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - dev_priv->saveLVDSPP_ON = I915_READ(LVDSPP_ON); - dev_priv->saveLVDSPP_OFF = I915_READ(LVDSPP_OFF); - dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE); + dev_priv->savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); + dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); + dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); /* FIXME: save TV & SDVO state */ @@ -337,19 +332,19 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFBC_CONTROL = I915_READ(FBC_CONTROL); /* Interrupt state */ - dev_priv->saveIIR = I915_READ(I915REG_INT_IDENTITY_R); - dev_priv->saveIER = I915_READ(I915REG_INT_ENABLE_R); - dev_priv->saveIMR = I915_READ(I915REG_INT_MASK_R); + dev_priv->saveIIR = I915_READ(IIR); + dev_priv->saveIER = I915_READ(IER); + dev_priv->saveIMR = I915_READ(IMR); /* VGA state */ - dev_priv->saveVCLK_DIVISOR_VGA0 = I915_READ(VCLK_DIVISOR_VGA0); - dev_priv->saveVCLK_DIVISOR_VGA1 = I915_READ(VCLK_DIVISOR_VGA1); - dev_priv->saveVCLK_POST_DIV = I915_READ(VCLK_POST_DIV); + dev_priv->saveVGA0 = I915_READ(VGA0); + dev_priv->saveVGA1 = I915_READ(VGA1); + dev_priv->saveVGA_PD = I915_READ(VGA_PD); dev_priv->saveVGACNTRL = I915_READ(VGACNTRL); /* Clock gating state */ dev_priv->saveD_STATE = I915_READ(D_STATE); - dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D); + dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS); /* Cache mode state */ dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); @@ -359,7 +354,7 @@ int i915_save_state(struct drm_device *dev) /* Scratch space */ for (i = 0; i < 16; i++) { - dev_priv->saveSWF0[i] = I915_READ(SWF0 + (i << 2)); + dev_priv->saveSWF0[i] = I915_READ(SWF00 + (i << 2)); dev_priv->saveSWF1[i] = I915_READ(SWF10 + (i << 2)); } for (i = 0; i < 3; i++) @@ -412,7 +407,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE); I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS); I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC); - I915_WRITE(DSPABASE, dev_priv->saveDSPABASE); + I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR); I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE); if (IS_I965G(dev)) { I915_WRITE(DSPASURF, dev_priv->saveDSPASURF); @@ -424,7 +419,7 @@ int i915_restore_state(struct drm_device *dev) i915_restore_palette(dev, PIPE_A); /* Enable the plane */ I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR); - I915_WRITE(DSPABASE, I915_READ(DSPABASE)); + I915_WRITE(DSPAADDR, I915_READ(DSPAADDR)); /* Pipe & plane B info */ if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) { @@ -454,7 +449,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE); I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS); I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC); - I915_WRITE(DSPBBASE, dev_priv->saveDSPBBASE); + I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR); I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE); if (IS_I965G(dev)) { I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF); @@ -466,7 +461,7 @@ int i915_restore_state(struct drm_device *dev) i915_restore_palette(dev, PIPE_B); /* Enable the plane */ I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR); - I915_WRITE(DSPBBASE, I915_READ(DSPBBASE)); + I915_WRITE(DSPBADDR, I915_READ(DSPBADDR)); /* CRT state */ I915_WRITE(ADPA, dev_priv->saveADPA); @@ -481,9 +476,9 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS); I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); - I915_WRITE(LVDSPP_ON, dev_priv->saveLVDSPP_ON); - I915_WRITE(LVDSPP_OFF, dev_priv->saveLVDSPP_OFF); - I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE); + I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON_DELAYS); + I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS); + I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); /* FIXME: restore TV & SDVO state */ @@ -496,14 +491,14 @@ int i915_restore_state(struct drm_device *dev) /* VGA state */ I915_WRITE(VGACNTRL, dev_priv->saveVGACNTRL); - I915_WRITE(VCLK_DIVISOR_VGA0, dev_priv->saveVCLK_DIVISOR_VGA0); - I915_WRITE(VCLK_DIVISOR_VGA1, dev_priv->saveVCLK_DIVISOR_VGA1); - I915_WRITE(VCLK_POST_DIV, dev_priv->saveVCLK_POST_DIV); + I915_WRITE(VGA0, dev_priv->saveVGA0); + I915_WRITE(VGA1, dev_priv->saveVGA1); + I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); DRM_UDELAY(150); /* Clock gating state */ I915_WRITE (D_STATE, dev_priv->saveD_STATE); - I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D); + I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS); /* Cache mode state */ I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000); @@ -512,7 +507,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE (MI_ARB_STATE, dev_priv->saveMI_ARB_STATE | 0xffff0000); for (i = 0; i < 16; i++) { - I915_WRITE(SWF0 + (i << 2), dev_priv->saveSWF0[i]); + I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]); I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]); } for (i = 0; i < 3; i++) -- cgit v1.2.3 From d726eb2e5e192f22e41e399d9133edcd7202f0c5 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 24 Jun 2008 12:57:21 -0700 Subject: i915: remove unused variable Leftover dev_priv from the move of the suspend/resume code into shared-core. --- linux-core/i915_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index c5f806b1..a1964f40 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -91,8 +91,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) static int i915_resume(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - pci_set_power_state(dev->pdev, PCI_D0); pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) -- cgit v1.2.3 From 5d27fd94afaaf434c3a92af0075420b550055bfb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Jun 2008 16:45:41 +1000 Subject: nv50: when destroying a channel make sure it's not still current on PFIFO We won't get a PFIFO context switch when the same channel ID is recreated if the hw still thinks the channel is already active, which causes fun issues. Should allow X to be stopped and started without tearing down the entire card state in lastclose(). --- shared-core/nv50_fifo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index edf4edbf..d6810666 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -289,6 +289,7 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; DRM_DEBUG("ch%d\n", chan->id); @@ -298,6 +299,9 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) if (chan->id == 0) nv50_fifo_channel_disable(dev, 127, 0); + if ((NV_READ(NV03_PFIFO_CACHE1_PUSH1) & 0xffff) == chan->id) + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 127); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } -- cgit v1.2.3 From e935925cd733fffef44b3e3210a875b57b3812e9 Mon Sep 17 00:00:00 2001 From: Jie Luo Date: Tue, 24 Jun 2008 10:38:31 -0700 Subject: i915: enable bus mastering on i915 at resume time On 9xx chips, bus mastering needs to be enabled at resume time for much of the chip to function. With this patch, vblank interrupts will work as expected on resume, along with other chip functions. Fixes kernel bugzilla #10844. Signed-off-by: Jie Luo Signed-off-by: Jesse Barnes --- linux-core/i915_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index a1964f40..be25239d 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -95,6 +95,7 @@ static int i915_resume(struct drm_device *dev) pci_restore_state(dev->pdev); if (pci_enable_device(dev->pdev)) return -1; + pci_set_master(dev->pdev); i915_restore_state(dev); -- cgit v1.2.3 From 727d4f1d1667e43b3558bd5f6ed6dc2cd9c29401 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 1 Jul 2008 12:25:16 -0700 Subject: i915: only use tiled blits on 965+ When scheduled swaps occur, we need to blit between front & back buffers. If the buffers are tiled, we need to set the appropriate XY_SRC_COPY tile bit, but only on 965 chips, since it will cause corruption on pre-965 (e.g. 945). Bug reported by and fix tested by Tomas Janousek . Signed-off-by: Jesse Barnes --- linux-core/i915_irq.c | 971 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 970 insertions(+), 1 deletion(-) mode change 120000 => 100644 linux-core/i915_irq.c diff --git a/linux-core/i915_irq.c b/linux-core/i915_irq.c deleted file mode 120000 index 2058a2e4..00000000 --- a/linux-core/i915_irq.c +++ /dev/null @@ -1 +0,0 @@ -../shared-core/i915_irq.c \ No newline at end of file diff --git a/linux-core/i915_irq.c b/linux-core/i915_irq.c new file mode 100644 index 00000000..28f9f6af --- /dev/null +++ b/linux-core/i915_irq.c @@ -0,0 +1,970 @@ +/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- + */ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#define MAX_NOPID ((u32)~0) + +/** + * i915_get_pipe - return the the pipe associated with a given plane + * @dev: DRM device + * @plane: plane to look for + * + * The Intel Mesa & 2D drivers call the vblank routines with a plane number + * rather than a pipe number, since they may not always be equal. This routine + * maps the given @plane back to a pipe number. + */ +static int +i915_get_pipe(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 dspcntr; + + dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); + + return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; +} + +/** + * i915_get_plane - return the the plane associated with a given pipe + * @dev: DRM device + * @pipe: pipe to look for + * + * The Intel Mesa & 2D drivers call the vblank routines with a plane number + * rather than a plane number, since they may not always be equal. This routine + * maps the given @pipe back to a plane number. + */ +static int +i915_get_plane(struct drm_device *dev, int pipe) +{ + if (i915_get_pipe(dev, 0) == pipe) + return 0; + return 1; +} + +/** + * i915_pipe_enabled - check if a pipe is enabled + * @dev: DRM device + * @pipe: pipe to check + * + * Reading certain registers when the pipe is disabled can hang the chip. + * Use this routine to make sure the PLL is running and the pipe is active + * before reading such registers if unsure. + */ +static int +i915_pipe_enabled(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; + + if (I915_READ(pipeconf) & PIPEACONF_ENABLE) + return 1; + + return 0; +} + +/** + * Emit a synchronous flip. + * + * This function must be called with the drawable spinlock held. + */ +static void +i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, + int plane) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + u16 x1, y1, x2, y2; + int pf_planes = 1 << plane; + + DRM_SPINLOCK_ASSERT(&dev->drw_lock); + + /* If the window is visible on the other plane, we have to flip on that + * plane as well. + */ + if (plane == 1) { + x1 = sarea_priv->planeA_x; + y1 = sarea_priv->planeA_y; + x2 = x1 + sarea_priv->planeA_w; + y2 = y1 + sarea_priv->planeA_h; + } else { + x1 = sarea_priv->planeB_x; + y1 = sarea_priv->planeB_y; + x2 = x1 + sarea_priv->planeB_w; + y2 = y1 + sarea_priv->planeB_h; + } + + if (x2 > 0 && y2 > 0) { + int i, num_rects = drw->num_rects; + struct drm_clip_rect *rect = drw->rects; + + for (i = 0; i < num_rects; i++) + if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || + rect[i].x2 <= x1 || rect[i].y2 <= y1)) { + pf_planes = 0x3; + + break; + } + } + + i915_dispatch_flip(dev, pf_planes, 1); +} + +/** + * Emit blits for scheduled buffer swaps. + * + * This function will be called with the HW lock held. + */ +static void i915_vblank_tasklet(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + struct list_head *list, *tmp, hits, *hit; + int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; + unsigned counter[2]; + struct drm_drawable_info *drw; + drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp, offsets[3]; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 src_pitch = sarea_priv->pitch * cpp; + u32 dst_pitch = sarea_priv->pitch * cpp; + /* COPY rop (0xcc), map cpp to magic color depth constants */ + u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); + RING_LOCALS; + + if (IS_I965G(dev) && sarea_priv->front_tiled) { + cmd |= XY_SRC_COPY_BLT_DST_TILED; + dst_pitch >>= 2; + } + if (IS_I965G(dev) && sarea_priv->back_tiled) { + cmd |= XY_SRC_COPY_BLT_SRC_TILED; + src_pitch >>= 2; + } + + counter[0] = drm_vblank_count(dev, 0); + counter[1] = drm_vblank_count(dev, 1); + + DRM_DEBUG("\n"); + + INIT_LIST_HEAD(&hits); + + nhits = nrects = 0; + + /* No irqsave/restore necessary. This tasklet may be run in an + * interrupt context or normal context, but we don't have to worry + * about getting interrupted by something acquiring the lock, because + * we are the interrupt context thing that acquires the lock. + */ + DRM_SPINLOCK(&dev_priv->swaps_lock); + + /* Find buffer swaps scheduled for this vertical blank */ + list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { + drm_i915_vbl_swap_t *vbl_swap = + list_entry(list, drm_i915_vbl_swap_t, head); + int pipe = i915_get_pipe(dev, vbl_swap->plane); + + if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) + continue; + + list_del(list); + dev_priv->swaps_pending--; + drm_vblank_put(dev, pipe); + + DRM_SPINUNLOCK(&dev_priv->swaps_lock); + DRM_SPINLOCK(&dev->drw_lock); + + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (!drw) { + DRM_SPINUNLOCK(&dev->drw_lock); + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + DRM_SPINLOCK(&dev_priv->swaps_lock); + continue; + } + + list_for_each(hit, &hits) { + drm_i915_vbl_swap_t *swap_cmp = + list_entry(hit, drm_i915_vbl_swap_t, head); + struct drm_drawable_info *drw_cmp = + drm_get_drawable_info(dev, swap_cmp->drw_id); + + if (drw_cmp && + drw_cmp->rects[0].y1 > drw->rects[0].y1) { + list_add_tail(list, hit); + break; + } + } + + DRM_SPINUNLOCK(&dev->drw_lock); + + /* List of hits was empty, or we reached the end of it */ + if (hit == &hits) + list_add_tail(list, hits.prev); + + nhits++; + + DRM_SPINLOCK(&dev_priv->swaps_lock); + } + + DRM_SPINUNLOCK(&dev_priv->swaps_lock); + + if (nhits == 0) { + return; + } + + i915_kernel_lost_context(dev); + + upper[0] = upper[1] = 0; + slice[0] = max(sarea_priv->planeA_h / nhits, 1); + slice[1] = max(sarea_priv->planeB_h / nhits, 1); + lower[0] = sarea_priv->planeA_y + slice[0]; + lower[1] = sarea_priv->planeB_y + slice[0]; + + offsets[0] = sarea_priv->front_offset; + offsets[1] = sarea_priv->back_offset; + offsets[2] = sarea_priv->third_offset; + num_pages = sarea_priv->third_handle ? 3 : 2; + + DRM_SPINLOCK(&dev->drw_lock); + + /* Emit blits for buffer swaps, partitioning both outputs into as many + * slices as there are buffer swaps scheduled in order to avoid tearing + * (based on the assumption that a single buffer swap would always + * complete before scanout starts). + */ + for (i = 0; i++ < nhits; + upper[0] = lower[0], lower[0] += slice[0], + upper[1] = lower[1], lower[1] += slice[1]) { + int init_drawrect = 1; + + if (i == nhits) + lower[0] = lower[1] = sarea_priv->height; + + list_for_each(hit, &hits) { + drm_i915_vbl_swap_t *swap_hit = + list_entry(hit, drm_i915_vbl_swap_t, head); + struct drm_clip_rect *rect; + int num_rects, plane, front, back; + unsigned short top, bottom; + + drw = drm_get_drawable_info(dev, swap_hit->drw_id); + + if (!drw) + continue; + + plane = swap_hit->plane; + + if (swap_hit->flip) { + i915_dispatch_vsync_flip(dev, drw, plane); + continue; + } + + if (init_drawrect) { + int width = sarea_priv->width; + int height = sarea_priv->height; + if (IS_I965G(dev)) { + BEGIN_LP_RING(4); + + OUT_RING(GFX_OP_DRAWRECT_INFO_I965); + OUT_RING(0); + OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); + OUT_RING(0); + + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); + OUT_RING(0); + OUT_RING(0); + + ADVANCE_LP_RING(); + } + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + init_drawrect = 0; + } + + rect = drw->rects; + top = upper[plane]; + bottom = lower[plane]; + + front = (dev_priv->sarea_priv->pf_current_page >> + (2 * plane)) & 0x3; + back = (front + 1) % num_pages; + + for (num_rects = drw->num_rects; num_rects--; rect++) { + int y1 = max(rect->y1, top); + int y2 = min(rect->y2, bottom); + + if (y1 >= y2) + continue; + + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(ropcpp | dst_pitch); + OUT_RING((y1 << 16) | rect->x1); + OUT_RING((y2 << 16) | rect->x2); + OUT_RING(offsets[front]); + OUT_RING((y1 << 16) | rect->x1); + OUT_RING(src_pitch); + OUT_RING(offsets[back]); + + ADVANCE_LP_RING(); + } + } + } + + DRM_SPINUNLOCK(&dev->drw_lock); + + list_for_each_safe(hit, tmp, &hits) { + drm_i915_vbl_swap_t *swap_hit = + list_entry(hit, drm_i915_vbl_swap_t, head); + + list_del(hit); + + drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); + } +} +#if 0 +static int i915_in_vblank(struct drm_device *dev, int pipe) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long pipedsl, vblank, vtotal; + unsigned long vbl_start, vbl_end, cur_line; + + pipedsl = pipe ? PIPEBDSL : PIPEADSL; + vblank = pipe ? VBLANK_B : VBLANK_A; + vtotal = pipe ? VTOTAL_B : VTOTAL_A; + + vbl_start = I915_READ(vblank) & VBLANK_START_MASK; + vbl_end = (I915_READ(vblank) >> VBLANK_END_SHIFT) & VBLANK_END_MASK; + + cur_line = I915_READ(pipedsl); + + if (cur_line >= vbl_start) + return 1; + + return 0; +} +#endif +u32 i915_get_vblank_counter(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned long high_frame; + unsigned long low_frame; + u32 high1, high2, low, count; + int pipe; + + pipe = i915_get_pipe(dev, plane); + high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; + low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; + + if (!i915_pipe_enabled(dev, pipe)) { + DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); + return 0; + } + + /* + * High & low register fields aren't synchronized, so make sure + * we get a low value that's stable across two reads of the high + * register. + */ + do { + high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> + PIPE_FRAME_LOW_SHIFT); + high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> + PIPE_FRAME_HIGH_SHIFT); + } while (high1 != high2); + + count = (high1 << 8) | low; + + /* + * If we're in the middle of the vblank period, the + * above regs won't have been updated yet, so return + * an incremented count to stay accurate + */ +#if 0 + if (i915_in_vblank(dev, pipe)) + count++; +#endif + /* count may be reset by other driver(e.g. 2D driver), + we have no way to know if it is wrapped or resetted + when count is zero. do a rough guess. + */ + if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) + dev->last_vblank[pipe] = 0; + + return count; +} + +irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) +{ + struct drm_device *dev = (struct drm_device *) arg; + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 iir; + u32 pipea_stats, pipeb_stats; + int vblank = 0; + + iir = I915_READ(IIR); +#if 0 + DRM_DEBUG("flag=%08x\n", iir); +#endif + if (iir == 0) { + DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", + iir, + I915_READ(IMR), + I915_READ(IER), + I915_READ(PIPEASTAT), + I915_READ(PIPEBSTAT)); + return IRQ_NONE; + } + + /* + * Clear the PIPE(A|B)STAT regs before the IIR otherwise + * we may get extra interrupts. + */ + if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { + pipea_stats = I915_READ(PIPEASTAT); + if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) + { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 0)); + } + + I915_WRITE(PIPEASTAT, pipea_stats); + } + if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { + pipeb_stats = I915_READ(PIPEBSTAT); + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| + PIPE_VBLANK_INTERRUPT_STATUS)) + { + vblank++; + drm_handle_vblank(dev, i915_get_plane(dev, 1)); + } + I915_WRITE(PIPEBSTAT, pipeb_stats); + } + + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + + I915_WRITE(IIR, iir); + (void) I915_READ(IIR); + + if (iir & I915_USER_INTERRUPT) { + DRM_WAKEUP(&dev_priv->irq_queue); +#ifdef I915_HAVE_FENCE + i915_fence_handler(dev); +#endif + } + + if (vblank) { + if (dev_priv->swaps_pending > 0) + drm_locked_tasklet(dev, i915_vblank_tasklet); + } + + return IRQ_HANDLED; +} + +int i915_emit_irq(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + i915_kernel_lost_context(dev); + + DRM_DEBUG("\n"); + + i915_emit_breadcrumb(dev); + + BEGIN_LP_RING(2); + OUT_RING(0); + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + + return dev_priv->counter; +} + +void i915_user_irq_on(drm_i915_private_t *dev_priv) +{ + DRM_SPINLOCK(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ + dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; + I915_WRITE(IER, dev_priv->irq_enable_reg); + } + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); + +} + +void i915_user_irq_off(drm_i915_private_t *dev_priv) +{ + DRM_SPINLOCK(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; + // I915_WRITE(IER, dev_priv->irq_enable_reg); + } + DRM_SPINUNLOCK(&dev_priv->user_irq_lock); +} + + +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; + int ret = 0; + + DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, + READ_BREADCRUMB(dev_priv)); + + if (READ_BREADCRUMB(dev_priv) >= irq_nr) + return 0; + + i915_user_irq_on(dev_priv); + DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, + READ_BREADCRUMB(dev_priv) >= irq_nr); + i915_user_irq_off(dev_priv); + + if (ret == -EBUSY) { + DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", + READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); + } + + if (dev_priv->sarea_priv) + dev_priv->sarea_priv->last_dispatch = + READ_BREADCRUMB(dev_priv); + return ret; +} + +/* Needs the lock as it touches the ring. + */ +int i915_irq_emit(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_emit_t *emit = data; + int result; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + result = i915_emit_irq(dev); + + if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { + DRM_ERROR("copy_to_user\n"); + return -EFAULT; + } + + return 0; +} + +/* Doesn't need the hardware lock. + */ +int i915_irq_wait(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_irq_wait_t *irqwait = data; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + return i915_wait_irq(dev, irqwait->irq_seq); +} + +int i915_enable_vblank(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe = i915_get_pipe(dev, plane); + u32 pipestat_reg = 0; + u32 pipestat; + + switch (pipe) { + case 0: + pipestat_reg = PIPEASTAT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + break; + case 1: + pipestat_reg = PIPEBSTAT; + dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + break; + default: + DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", + pipe); + break; + } + + if (pipestat_reg) + { + pipestat = I915_READ (pipestat_reg); + /* + * Older chips didn't have the start vblank interrupt, + * but + */ + if (IS_I965G (dev)) + pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; + else + pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; + /* + * Clear any pending status + */ + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); + I915_WRITE(pipestat_reg, pipestat); + } + I915_WRITE(IER, dev_priv->irq_enable_reg); + + return 0; +} + +void i915_disable_vblank(struct drm_device *dev, int plane) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int pipe = i915_get_pipe(dev, plane); + u32 pipestat_reg = 0; + u32 pipestat; + + switch (pipe) { + case 0: + pipestat_reg = PIPEASTAT; + dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; + break; + case 1: + pipestat_reg = PIPEBSTAT; + dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; + break; + default: + DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", + pipe); + break; + } + + I915_WRITE(IER, dev_priv->irq_enable_reg); + + if (pipestat_reg) + { + pipestat = I915_READ (pipestat_reg); + pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | + PIPE_VBLANK_INTERRUPT_ENABLE); + /* + * Clear any pending status + */ + pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | + PIPE_VBLANK_INTERRUPT_STATUS); + I915_WRITE(pipestat_reg, pipestat); + } +} + +static void i915_enable_interrupt (struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; + + I915_WRITE(IER, dev_priv->irq_enable_reg); + dev_priv->irq_enabled = 1; +} + +/* Set the vblank monitor pipe + */ +int i915_vblank_pipe_set(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t *pipe = data; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); + return -EINVAL; + } + + dev_priv->vblank_pipe = pipe->pipe; + + return 0; +} + +int i915_vblank_pipe_get(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_pipe_t *pipe = data; + u16 flag; + + if (!dev_priv) { + DRM_ERROR("called with no initialization\n"); + return -EINVAL; + } + + flag = I915_READ(IER); + + pipe->pipe = 0; + if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) + pipe->pipe |= DRM_I915_VBLANK_PIPE_A; + if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) + pipe->pipe |= DRM_I915_VBLANK_PIPE_B; + + return 0; +} + +/** + * Schedule buffer swap at given vertical blank. + */ +int i915_vblank_swap(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_swap_t *swap = data; + drm_i915_vbl_swap_t *vbl_swap; + unsigned int pipe, seqtype, curseq, plane; + unsigned long irqflags; + struct list_head *list; + int ret; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __func__); + return -EINVAL; + } + + if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { + DRM_DEBUG("Rotation not supported\n"); + return -EINVAL; + } + + if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | + _DRM_VBLANK_FLIP)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); + return -EINVAL; + } + + plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + pipe = i915_get_pipe(dev, plane); + + seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); + return -EINVAL; + } + + DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags); + + /* It makes no sense to schedule a swap for a drawable that doesn't have + * valid information at this point. E.g. this could mean that the X + * server is too old to push drawable information to the DRM, in which + * case all such swaps would become ineffective. + */ + if (!drm_get_drawable_info(dev, swap->drawable)) { + DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); + return -EINVAL; + } + + DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + + drm_update_vblank_count(dev, pipe); + curseq = drm_vblank_count(dev, pipe); + + if (seqtype == _DRM_VBLANK_RELATIVE) + swap->sequence += curseq; + + if ((curseq - swap->sequence) <= (1<<23)) { + if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) { + swap->sequence = curseq + 1; + } else { + DRM_DEBUG("Missed target sequence\n"); + return -EINVAL; + } + } + + if (swap->seqtype & _DRM_VBLANK_FLIP) { + swap->sequence--; + + if ((curseq - swap->sequence) <= (1<<23)) { + struct drm_drawable_info *drw; + + LOCK_TEST_WITH_RETURN(dev, file_priv); + + DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags); + + drw = drm_get_drawable_info(dev, swap->drawable); + + if (!drw) { + DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, + irqflags); + DRM_DEBUG("Invalid drawable ID %d\n", + swap->drawable); + return -EINVAL; + } + + i915_dispatch_vsync_flip(dev, drw, plane); + + DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + + return 0; + } + } + + DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); + + list_for_each(list, &dev_priv->vbl_swaps.head) { + vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + + if (vbl_swap->drw_id == swap->drawable && + vbl_swap->plane == plane && + vbl_swap->sequence == swap->sequence) { + vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); + DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Already scheduled\n"); + return 0; + } + } + + DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); + + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return -EBUSY; + } + + vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER); + + if (!vbl_swap) { + DRM_ERROR("Failed to allocate memory to queue swap\n"); + return -ENOMEM; + } + + DRM_DEBUG("\n"); + + ret = drm_vblank_get(dev, pipe); + if (ret) { + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + return ret; + } + + vbl_swap->drw_id = swap->drawable; + vbl_swap->plane = plane; + vbl_swap->sequence = swap->sequence; + vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); + + if (vbl_swap->flip) + swap->sequence++; + + DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); + + list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head); + dev_priv->swaps_pending++; + + DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); + + return 0; +} + +/* drm_dma.h hooks +*/ +void i915_driver_irq_preinstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + + I915_WRITE16(HWSTAM, 0xeffe); + I915_WRITE16(IMR, 0x0); + I915_WRITE16(IER, 0x0); +} + +int i915_driver_irq_postinstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + int ret, num_pipes = 2; + + DRM_SPININIT(&dev_priv->swaps_lock, "swap"); + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + + DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); + dev_priv->user_irq_refcount = 0; + dev_priv->irq_enable_reg = 0; + + ret = drm_vblank_init(dev, num_pipes); + if (ret) + return ret; + + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + + i915_enable_interrupt(dev); + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); + return 0; +} + +void i915_driver_irq_uninstall(struct drm_device * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 temp; + + if (!dev_priv) + return; + + dev_priv->irq_enabled = 0; + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + + temp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, temp); + temp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, temp); + temp = I915_READ(IIR); + I915_WRITE(IIR, temp); +} -- cgit v1.2.3 From 94dcc83ad2e8f848a3cac6cdc6f123e676e91cf8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 1 Jul 2008 16:09:02 -0700 Subject: Revert "i915: only use tiled blits on 965+" This reverts commit 727d4f1d1667e43b3558bd5f6ed6dc2cd9c29401, somehow git deleted the symlink and replaced it with the file. --- linux-core/i915_irq.c | 971 +------------------------------------------------- 1 file changed, 1 insertion(+), 970 deletions(-) mode change 100644 => 120000 linux-core/i915_irq.c diff --git a/linux-core/i915_irq.c b/linux-core/i915_irq.c deleted file mode 100644 index 28f9f6af..00000000 --- a/linux-core/i915_irq.c +++ /dev/null @@ -1,970 +0,0 @@ -/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- - */ -/* - * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "drmP.h" -#include "drm.h" -#include "i915_drm.h" -#include "i915_drv.h" - -#define MAX_NOPID ((u32)~0) - -/** - * i915_get_pipe - return the the pipe associated with a given plane - * @dev: DRM device - * @plane: plane to look for - * - * The Intel Mesa & 2D drivers call the vblank routines with a plane number - * rather than a pipe number, since they may not always be equal. This routine - * maps the given @plane back to a pipe number. - */ -static int -i915_get_pipe(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 dspcntr; - - dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR); - - return dspcntr & DISPPLANE_SEL_PIPE_MASK ? 1 : 0; -} - -/** - * i915_get_plane - return the the plane associated with a given pipe - * @dev: DRM device - * @pipe: pipe to look for - * - * The Intel Mesa & 2D drivers call the vblank routines with a plane number - * rather than a plane number, since they may not always be equal. This routine - * maps the given @pipe back to a plane number. - */ -static int -i915_get_plane(struct drm_device *dev, int pipe) -{ - if (i915_get_pipe(dev, 0) == pipe) - return 0; - return 1; -} - -/** - * i915_pipe_enabled - check if a pipe is enabled - * @dev: DRM device - * @pipe: pipe to check - * - * Reading certain registers when the pipe is disabled can hang the chip. - * Use this routine to make sure the PLL is running and the pipe is active - * before reading such registers if unsure. - */ -static int -i915_pipe_enabled(struct drm_device *dev, int pipe) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF; - - if (I915_READ(pipeconf) & PIPEACONF_ENABLE) - return 1; - - return 0; -} - -/** - * Emit a synchronous flip. - * - * This function must be called with the drawable spinlock held. - */ -static void -i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw, - int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u16 x1, y1, x2, y2; - int pf_planes = 1 << plane; - - DRM_SPINLOCK_ASSERT(&dev->drw_lock); - - /* If the window is visible on the other plane, we have to flip on that - * plane as well. - */ - if (plane == 1) { - x1 = sarea_priv->planeA_x; - y1 = sarea_priv->planeA_y; - x2 = x1 + sarea_priv->planeA_w; - y2 = y1 + sarea_priv->planeA_h; - } else { - x1 = sarea_priv->planeB_x; - y1 = sarea_priv->planeB_y; - x2 = x1 + sarea_priv->planeB_w; - y2 = y1 + sarea_priv->planeB_h; - } - - if (x2 > 0 && y2 > 0) { - int i, num_rects = drw->num_rects; - struct drm_clip_rect *rect = drw->rects; - - for (i = 0; i < num_rects; i++) - if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 || - rect[i].x2 <= x1 || rect[i].y2 <= y1)) { - pf_planes = 0x3; - - break; - } - } - - i915_dispatch_flip(dev, pf_planes, 1); -} - -/** - * Emit blits for scheduled buffer swaps. - * - * This function will be called with the HW lock held. - */ -static void i915_vblank_tasklet(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - struct list_head *list, *tmp, hits, *hit; - int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages; - unsigned counter[2]; - struct drm_drawable_info *drw; - drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; - u32 cpp = dev_priv->cpp, offsets[3]; - u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | - XY_SRC_COPY_BLT_WRITE_ALPHA | - XY_SRC_COPY_BLT_WRITE_RGB) - : XY_SRC_COPY_BLT_CMD; - u32 src_pitch = sarea_priv->pitch * cpp; - u32 dst_pitch = sarea_priv->pitch * cpp; - /* COPY rop (0xcc), map cpp to magic color depth constants */ - u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); - RING_LOCALS; - - if (IS_I965G(dev) && sarea_priv->front_tiled) { - cmd |= XY_SRC_COPY_BLT_DST_TILED; - dst_pitch >>= 2; - } - if (IS_I965G(dev) && sarea_priv->back_tiled) { - cmd |= XY_SRC_COPY_BLT_SRC_TILED; - src_pitch >>= 2; - } - - counter[0] = drm_vblank_count(dev, 0); - counter[1] = drm_vblank_count(dev, 1); - - DRM_DEBUG("\n"); - - INIT_LIST_HEAD(&hits); - - nhits = nrects = 0; - - /* No irqsave/restore necessary. This tasklet may be run in an - * interrupt context or normal context, but we don't have to worry - * about getting interrupted by something acquiring the lock, because - * we are the interrupt context thing that acquires the lock. - */ - DRM_SPINLOCK(&dev_priv->swaps_lock); - - /* Find buffer swaps scheduled for this vertical blank */ - list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { - drm_i915_vbl_swap_t *vbl_swap = - list_entry(list, drm_i915_vbl_swap_t, head); - int pipe = i915_get_pipe(dev, vbl_swap->plane); - - if ((counter[pipe] - vbl_swap->sequence) > (1<<23)) - continue; - - list_del(list); - dev_priv->swaps_pending--; - drm_vblank_put(dev, pipe); - - DRM_SPINUNLOCK(&dev_priv->swaps_lock); - DRM_SPINLOCK(&dev->drw_lock); - - drw = drm_get_drawable_info(dev, vbl_swap->drw_id); - - if (!drw) { - DRM_SPINUNLOCK(&dev->drw_lock); - drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); - DRM_SPINLOCK(&dev_priv->swaps_lock); - continue; - } - - list_for_each(hit, &hits) { - drm_i915_vbl_swap_t *swap_cmp = - list_entry(hit, drm_i915_vbl_swap_t, head); - struct drm_drawable_info *drw_cmp = - drm_get_drawable_info(dev, swap_cmp->drw_id); - - if (drw_cmp && - drw_cmp->rects[0].y1 > drw->rects[0].y1) { - list_add_tail(list, hit); - break; - } - } - - DRM_SPINUNLOCK(&dev->drw_lock); - - /* List of hits was empty, or we reached the end of it */ - if (hit == &hits) - list_add_tail(list, hits.prev); - - nhits++; - - DRM_SPINLOCK(&dev_priv->swaps_lock); - } - - DRM_SPINUNLOCK(&dev_priv->swaps_lock); - - if (nhits == 0) { - return; - } - - i915_kernel_lost_context(dev); - - upper[0] = upper[1] = 0; - slice[0] = max(sarea_priv->planeA_h / nhits, 1); - slice[1] = max(sarea_priv->planeB_h / nhits, 1); - lower[0] = sarea_priv->planeA_y + slice[0]; - lower[1] = sarea_priv->planeB_y + slice[0]; - - offsets[0] = sarea_priv->front_offset; - offsets[1] = sarea_priv->back_offset; - offsets[2] = sarea_priv->third_offset; - num_pages = sarea_priv->third_handle ? 3 : 2; - - DRM_SPINLOCK(&dev->drw_lock); - - /* Emit blits for buffer swaps, partitioning both outputs into as many - * slices as there are buffer swaps scheduled in order to avoid tearing - * (based on the assumption that a single buffer swap would always - * complete before scanout starts). - */ - for (i = 0; i++ < nhits; - upper[0] = lower[0], lower[0] += slice[0], - upper[1] = lower[1], lower[1] += slice[1]) { - int init_drawrect = 1; - - if (i == nhits) - lower[0] = lower[1] = sarea_priv->height; - - list_for_each(hit, &hits) { - drm_i915_vbl_swap_t *swap_hit = - list_entry(hit, drm_i915_vbl_swap_t, head); - struct drm_clip_rect *rect; - int num_rects, plane, front, back; - unsigned short top, bottom; - - drw = drm_get_drawable_info(dev, swap_hit->drw_id); - - if (!drw) - continue; - - plane = swap_hit->plane; - - if (swap_hit->flip) { - i915_dispatch_vsync_flip(dev, drw, plane); - continue; - } - - if (init_drawrect) { - int width = sarea_priv->width; - int height = sarea_priv->height; - if (IS_I965G(dev)) { - BEGIN_LP_RING(4); - - OUT_RING(GFX_OP_DRAWRECT_INFO_I965); - OUT_RING(0); - OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); - OUT_RING(0); - - ADVANCE_LP_RING(); - } else { - BEGIN_LP_RING(6); - - OUT_RING(GFX_OP_DRAWRECT_INFO); - OUT_RING(0); - OUT_RING(0); - OUT_RING(((width - 1) & 0xffff) | ((height - 1) << 16)); - OUT_RING(0); - OUT_RING(0); - - ADVANCE_LP_RING(); - } - - sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; - - init_drawrect = 0; - } - - rect = drw->rects; - top = upper[plane]; - bottom = lower[plane]; - - front = (dev_priv->sarea_priv->pf_current_page >> - (2 * plane)) & 0x3; - back = (front + 1) % num_pages; - - for (num_rects = drw->num_rects; num_rects--; rect++) { - int y1 = max(rect->y1, top); - int y2 = min(rect->y2, bottom); - - if (y1 >= y2) - continue; - - BEGIN_LP_RING(8); - - OUT_RING(cmd); - OUT_RING(ropcpp | dst_pitch); - OUT_RING((y1 << 16) | rect->x1); - OUT_RING((y2 << 16) | rect->x2); - OUT_RING(offsets[front]); - OUT_RING((y1 << 16) | rect->x1); - OUT_RING(src_pitch); - OUT_RING(offsets[back]); - - ADVANCE_LP_RING(); - } - } - } - - DRM_SPINUNLOCK(&dev->drw_lock); - - list_for_each_safe(hit, tmp, &hits) { - drm_i915_vbl_swap_t *swap_hit = - list_entry(hit, drm_i915_vbl_swap_t, head); - - list_del(hit); - - drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); - } -} -#if 0 -static int i915_in_vblank(struct drm_device *dev, int pipe) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long pipedsl, vblank, vtotal; - unsigned long vbl_start, vbl_end, cur_line; - - pipedsl = pipe ? PIPEBDSL : PIPEADSL; - vblank = pipe ? VBLANK_B : VBLANK_A; - vtotal = pipe ? VTOTAL_B : VTOTAL_A; - - vbl_start = I915_READ(vblank) & VBLANK_START_MASK; - vbl_end = (I915_READ(vblank) >> VBLANK_END_SHIFT) & VBLANK_END_MASK; - - cur_line = I915_READ(pipedsl); - - if (cur_line >= vbl_start) - return 1; - - return 0; -} -#endif -u32 i915_get_vblank_counter(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long high_frame; - unsigned long low_frame; - u32 high1, high2, low, count; - int pipe; - - pipe = i915_get_pipe(dev, plane); - high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH; - low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL; - - if (!i915_pipe_enabled(dev, pipe)) { - DRM_ERROR("trying to get vblank count for disabled pipe %d\n", pipe); - return 0; - } - - /* - * High & low register fields aren't synchronized, so make sure - * we get a low value that's stable across two reads of the high - * register. - */ - do { - high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - low = ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >> - PIPE_FRAME_LOW_SHIFT); - high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >> - PIPE_FRAME_HIGH_SHIFT); - } while (high1 != high2); - - count = (high1 << 8) | low; - - /* - * If we're in the middle of the vblank period, the - * above regs won't have been updated yet, so return - * an incremented count to stay accurate - */ -#if 0 - if (i915_in_vblank(dev, pipe)) - count++; -#endif - /* count may be reset by other driver(e.g. 2D driver), - we have no way to know if it is wrapped or resetted - when count is zero. do a rough guess. - */ - if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) - dev->last_vblank[pipe] = 0; - - return count; -} - -irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) -{ - struct drm_device *dev = (struct drm_device *) arg; - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 iir; - u32 pipea_stats, pipeb_stats; - int vblank = 0; - - iir = I915_READ(IIR); -#if 0 - DRM_DEBUG("flag=%08x\n", iir); -#endif - if (iir == 0) { - DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", - iir, - I915_READ(IMR), - I915_READ(IER), - I915_READ(PIPEASTAT), - I915_READ(PIPEBSTAT)); - return IRQ_NONE; - } - - /* - * Clear the PIPE(A|B)STAT regs before the IIR otherwise - * we may get extra interrupts. - */ - if (iir & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) { - pipea_stats = I915_READ(PIPEASTAT); - if (pipea_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 0)); - } - - I915_WRITE(PIPEASTAT, pipea_stats); - } - if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { - pipeb_stats = I915_READ(PIPEBSTAT); - if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| - PIPE_VBLANK_INTERRUPT_STATUS)) - { - vblank++; - drm_handle_vblank(dev, i915_get_plane(dev, 1)); - } - I915_WRITE(PIPEBSTAT, pipeb_stats); - } - - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - - I915_WRITE(IIR, iir); - (void) I915_READ(IIR); - - if (iir & I915_USER_INTERRUPT) { - DRM_WAKEUP(&dev_priv->irq_queue); -#ifdef I915_HAVE_FENCE - i915_fence_handler(dev); -#endif - } - - if (vblank) { - if (dev_priv->swaps_pending > 0) - drm_locked_tasklet(dev, i915_vblank_tasklet); - } - - return IRQ_HANDLED; -} - -int i915_emit_irq(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - RING_LOCALS; - - i915_kernel_lost_context(dev); - - DRM_DEBUG("\n"); - - i915_emit_breadcrumb(dev); - - BEGIN_LP_RING(2); - OUT_RING(0); - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); - - return dev_priv->counter; -} - -void i915_user_irq_on(drm_i915_private_t *dev_priv) -{ - DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - I915_WRITE(IER, dev_priv->irq_enable_reg); - } - DRM_SPINUNLOCK(&dev_priv->user_irq_lock); - -} - -void i915_user_irq_off(drm_i915_private_t *dev_priv) -{ - DRM_SPINLOCK(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - // dev_priv->irq_enable_reg &= ~I915_USER_INTERRUPT; - // I915_WRITE(IER, dev_priv->irq_enable_reg); - } - DRM_SPINUNLOCK(&dev_priv->user_irq_lock); -} - - -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; - int ret = 0; - - DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, - READ_BREADCRUMB(dev_priv)); - - if (READ_BREADCRUMB(dev_priv) >= irq_nr) - return 0; - - i915_user_irq_on(dev_priv); - DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, - READ_BREADCRUMB(dev_priv) >= irq_nr); - i915_user_irq_off(dev_priv); - - if (ret == -EBUSY) { - DRM_ERROR("EBUSY -- rec: %d emitted: %d\n", - READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); - } - - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - return ret; -} - -/* Needs the lock as it touches the ring. - */ -int i915_irq_emit(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_emit_t *emit = data; - int result; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - result = i915_emit_irq(dev); - - if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { - DRM_ERROR("copy_to_user\n"); - return -EFAULT; - } - - return 0; -} - -/* Doesn't need the hardware lock. - */ -int i915_irq_wait(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_irq_wait_t *irqwait = data; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - return i915_wait_irq(dev, irqwait->irq_seq); -} - -int i915_enable_vblank(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int pipe = i915_get_pipe(dev, plane); - u32 pipestat_reg = 0; - u32 pipestat; - - switch (pipe) { - case 0: - pipestat_reg = PIPEASTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; - break; - case 1: - pipestat_reg = PIPEBSTAT; - dev_priv->irq_enable_reg |= I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - break; - default: - DRM_ERROR("tried to enable vblank on non-existent pipe %d\n", - pipe); - break; - } - - if (pipestat_reg) - { - pipestat = I915_READ (pipestat_reg); - /* - * Older chips didn't have the start vblank interrupt, - * but - */ - if (IS_I965G (dev)) - pipestat |= PIPE_START_VBLANK_INTERRUPT_ENABLE; - else - pipestat |= PIPE_VBLANK_INTERRUPT_ENABLE; - /* - * Clear any pending status - */ - pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | - PIPE_VBLANK_INTERRUPT_STATUS); - I915_WRITE(pipestat_reg, pipestat); - } - I915_WRITE(IER, dev_priv->irq_enable_reg); - - return 0; -} - -void i915_disable_vblank(struct drm_device *dev, int plane) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int pipe = i915_get_pipe(dev, plane); - u32 pipestat_reg = 0; - u32 pipestat; - - switch (pipe) { - case 0: - pipestat_reg = PIPEASTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_A_EVENT_INTERRUPT; - break; - case 1: - pipestat_reg = PIPEBSTAT; - dev_priv->irq_enable_reg &= ~I915_DISPLAY_PIPE_B_EVENT_INTERRUPT; - break; - default: - DRM_ERROR("tried to disable vblank on non-existent pipe %d\n", - pipe); - break; - } - - I915_WRITE(IER, dev_priv->irq_enable_reg); - - if (pipestat_reg) - { - pipestat = I915_READ (pipestat_reg); - pipestat &= ~(PIPE_START_VBLANK_INTERRUPT_ENABLE | - PIPE_VBLANK_INTERRUPT_ENABLE); - /* - * Clear any pending status - */ - pipestat |= (PIPE_START_VBLANK_INTERRUPT_STATUS | - PIPE_VBLANK_INTERRUPT_STATUS); - I915_WRITE(pipestat_reg, pipestat); - } -} - -static void i915_enable_interrupt (struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - - dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; - - I915_WRITE(IER, dev_priv->irq_enable_reg); - dev_priv->irq_enabled = 1; -} - -/* Set the vblank monitor pipe - */ -int i915_vblank_pipe_set(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); - return -EINVAL; - } - - dev_priv->vblank_pipe = pipe->pipe; - - return 0; -} - -int i915_vblank_pipe_get(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; - u16 flag; - - if (!dev_priv) { - DRM_ERROR("called with no initialization\n"); - return -EINVAL; - } - - flag = I915_READ(IER); - - pipe->pipe = 0; - if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) - pipe->pipe |= DRM_I915_VBLANK_PIPE_A; - if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) - pipe->pipe |= DRM_I915_VBLANK_PIPE_B; - - return 0; -} - -/** - * Schedule buffer swap at given vertical blank. - */ -int i915_vblank_swap(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_swap_t *swap = data; - drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, curseq, plane; - unsigned long irqflags; - struct list_head *list; - int ret; - - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __func__); - return -EINVAL; - } - - if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) { - DRM_DEBUG("Rotation not supported\n"); - return -EINVAL; - } - - if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS | - _DRM_VBLANK_FLIP)) { - DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype); - return -EINVAL; - } - - plane = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; - pipe = i915_get_pipe(dev, plane); - - seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - - if (!(dev_priv->vblank_pipe & (1 << pipe))) { - DRM_ERROR("Invalid pipe %d\n", pipe); - return -EINVAL; - } - - DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags); - - /* It makes no sense to schedule a swap for a drawable that doesn't have - * valid information at this point. E.g. this could mean that the X - * server is too old to push drawable information to the DRM, in which - * case all such swaps would become ineffective. - */ - if (!drm_get_drawable_info(dev, swap->drawable)) { - DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); - DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); - return -EINVAL; - } - - DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); - - drm_update_vblank_count(dev, pipe); - curseq = drm_vblank_count(dev, pipe); - - if (seqtype == _DRM_VBLANK_RELATIVE) - swap->sequence += curseq; - - if ((curseq - swap->sequence) <= (1<<23)) { - if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) { - swap->sequence = curseq + 1; - } else { - DRM_DEBUG("Missed target sequence\n"); - return -EINVAL; - } - } - - if (swap->seqtype & _DRM_VBLANK_FLIP) { - swap->sequence--; - - if ((curseq - swap->sequence) <= (1<<23)) { - struct drm_drawable_info *drw; - - LOCK_TEST_WITH_RETURN(dev, file_priv); - - DRM_SPINLOCK_IRQSAVE(&dev->drw_lock, irqflags); - - drw = drm_get_drawable_info(dev, swap->drawable); - - if (!drw) { - DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, - irqflags); - DRM_DEBUG("Invalid drawable ID %d\n", - swap->drawable); - return -EINVAL; - } - - i915_dispatch_vsync_flip(dev, drw, plane); - - DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); - - return 0; - } - } - - DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); - - list_for_each(list, &dev_priv->vbl_swaps.head) { - vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); - - if (vbl_swap->drw_id == swap->drawable && - vbl_swap->plane == plane && - vbl_swap->sequence == swap->sequence) { - vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); - DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); - DRM_DEBUG("Already scheduled\n"); - return 0; - } - } - - DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); - - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return -EBUSY; - } - - vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER); - - if (!vbl_swap) { - DRM_ERROR("Failed to allocate memory to queue swap\n"); - return -ENOMEM; - } - - DRM_DEBUG("\n"); - - ret = drm_vblank_get(dev, pipe); - if (ret) { - drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); - return ret; - } - - vbl_swap->drw_id = swap->drawable; - vbl_swap->plane = plane; - vbl_swap->sequence = swap->sequence; - vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP); - - if (vbl_swap->flip) - swap->sequence++; - - DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags); - - list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head); - dev_priv->swaps_pending++; - - DRM_SPINUNLOCK_IRQRESTORE(&dev_priv->swaps_lock, irqflags); - - return 0; -} - -/* drm_dma.h hooks -*/ -void i915_driver_irq_preinstall(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - - I915_WRITE16(HWSTAM, 0xeffe); - I915_WRITE16(IMR, 0x0); - I915_WRITE16(IER, 0x0); -} - -int i915_driver_irq_postinstall(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int ret, num_pipes = 2; - - DRM_SPININIT(&dev_priv->swaps_lock, "swap"); - INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); - dev_priv->swaps_pending = 0; - - DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = 0; - - ret = drm_vblank_init(dev, num_pipes); - if (ret) - return ret; - - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - - i915_enable_interrupt(dev); - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); - - /* - * Initialize the hardware status page IRQ location. - */ - - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); - return 0; -} - -void i915_driver_irq_uninstall(struct drm_device * dev) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 temp; - - if (!dev_priv) - return; - - dev_priv->irq_enabled = 0; - I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(IMR, 0xffffffff); - I915_WRITE(IER, 0x0); - - temp = I915_READ(PIPEASTAT); - I915_WRITE(PIPEASTAT, temp); - temp = I915_READ(PIPEBSTAT); - I915_WRITE(PIPEBSTAT, temp); - temp = I915_READ(IIR); - I915_WRITE(IIR, temp); -} diff --git a/linux-core/i915_irq.c b/linux-core/i915_irq.c new file mode 120000 index 00000000..2058a2e4 --- /dev/null +++ b/linux-core/i915_irq.c @@ -0,0 +1 @@ +../shared-core/i915_irq.c \ No newline at end of file -- cgit v1.2.3 From 301d984ea80cb250460d6701c4373cf0af8bf59e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 1 Jul 2008 16:10:01 -0700 Subject: i915: only use tiled blits on 965+ When scheduled swaps occur, we need to blit between front & back buffers. I the buffers are tiled, we need to set the appropriate XY_SRC_COPY tile bit, only on 965 chips, since it will cause corruption on pre-965 (e.g. 945). Bug reported by and fix tested by Tomas Janousek . Signed-off-by: Jesse Barnes --- shared-core/i915_irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 0bf01bdd..28f9f6af 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -162,11 +162,11 @@ static void i915_vblank_tasklet(struct drm_device *dev) u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24); RING_LOCALS; - if (sarea_priv->front_tiled) { + if (IS_I965G(dev) && sarea_priv->front_tiled) { cmd |= XY_SRC_COPY_BLT_DST_TILED; dst_pitch >>= 2; } - if (sarea_priv->back_tiled) { + if (IS_I965G(dev) && sarea_priv->back_tiled) { cmd |= XY_SRC_COPY_BLT_SRC_TILED; src_pitch >>= 2; } -- cgit v1.2.3 From 401f77a2ef1d55feaccc13cdae1e5379f4cfec7e Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Thu, 3 Jul 2008 00:49:19 +0800 Subject: i915: official name for GM45 chipset Signed-off-by: Zhenyu Wang --- shared-core/drm_pciids.txt | 2 +- shared-core/i915_drv.h | 6 +++--- shared-core/i915_suspend.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index dd88ebab..205fc539 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -394,7 +394,7 @@ 0x8086 0x29C2 CHIP_I9XX|CHIP_I915 "Intel G33" 0x8086 0x29B2 CHIP_I9XX|CHIP_I915 "Intel Q35" 0x8086 0x29D2 CHIP_I9XX|CHIP_I915 "Intel Q33" -0x8086 0x2A42 CHIP_I9XX|CHIP_I965 "Intel Integrated Graphics Device" +0x8086 0x2A42 CHIP_I9XX|CHIP_I965 "Mobile Intel® GM45 Express Chipset" 0x8086 0x2E02 CHIP_I9XX|CHIP_I965 "Intel Integrated Graphics Device" 0x8086 0x2E12 CHIP_I9XX|CHIP_I965 "Intel Q45/Q43" 0x8086 0x2E22 CHIP_I9XX|CHIP_I965 "Intel G45/G43" diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 3ba74db8..fa3305ba 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -1801,7 +1801,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02) -#define IS_IGD_GM(dev) ((dev)->pci_device == 0x2A42) +#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ (dev)->pci_device == 0x2E12 || \ @@ -1815,8 +1815,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev)) #define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ - IS_I945GM(dev) || IS_I965GM(dev) || IS_IGD_GM(dev)) + IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev)) -#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_IGD_GM(dev) || IS_G4X(dev)) +#define I915_NEED_GFX_HWS(dev) (IS_G33(dev) || IS_GM45(dev) || IS_G4X(dev)) #endif diff --git a/shared-core/i915_suspend.c b/shared-core/i915_suspend.c index 63cd54a2..5e759b15 100644 --- a/shared-core/i915_suspend.c +++ b/shared-core/i915_suspend.c @@ -299,7 +299,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE); dev_priv->saveDSPBPOS = I915_READ(DSPBPOS); dev_priv->saveDSPBADDR = I915_READ(DSPBADDR); - if (IS_I965GM(dev) || IS_IGD_GM(dev)) { + if (IS_I965GM(dev) || IS_GM45(dev)) { dev_priv->saveDSPBSURF = I915_READ(DSPBSURF); dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF); } -- cgit v1.2.3 From c7ed2c67916ee8058301c53b9d4690d81728fb95 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Jun 2008 04:39:32 +1000 Subject: nouveau: interface changes for nv5x 3d --- shared-core/nouveau_drm.h | 20 ++++++++++---- shared-core/nouveau_drv.h | 4 ++- shared-core/nouveau_fifo.c | 1 + shared-core/nouveau_mem.c | 66 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index bbb51bc4..4b5869ad 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -25,7 +25,7 @@ #ifndef __NOUVEAU_DRM_H__ #define __NOUVEAU_DRM_H__ -#define NOUVEAU_DRM_HEADER_PATCHLEVEL 10 +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 11 struct drm_nouveau_channel_alloc { uint32_t fb_ctxdma_handle; @@ -85,10 +85,12 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_PINNED 0x00000040 #define NOUVEAU_MEM_USER_BACKED 0x00000080 #define NOUVEAU_MEM_MAPPED 0x00000100 -#define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ -#define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ -#define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ -#define NOUVEAU_MEM_USER 0x00001000 /* internal */ +#define NOUVEAU_MEM_TILE 0x00000200 +#define NOUVEAU_MEM_TILE_ZETA 0x00000400 +#define NOUVEAU_MEM_INSTANCE 0x01000000 /* internal */ +#define NOUVEAU_MEM_NOTIFIER 0x02000000 /* internal */ +#define NOUVEAU_MEM_NOVM 0x04000000 /* internal */ +#define NOUVEAU_MEM_USER 0x08000000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ NOUVEAU_MEM_NOVM | \ @@ -107,6 +109,13 @@ struct drm_nouveau_mem_free { int flags; }; +struct drm_nouveau_mem_tile { + uint64_t offset; + uint64_t delta; + uint64_t size; + int flags; +}; + /* FIXME : maybe unify {GET,SET}PARAMs */ #define NOUVEAU_GETPARAM_PCI_VENDOR 3 #define NOUVEAU_GETPARAM_PCI_DEVICE 4 @@ -168,5 +177,6 @@ struct drm_nouveau_sarea { #define DRM_NOUVEAU_GPUOBJ_FREE 0x07 #define DRM_NOUVEAU_MEM_ALLOC 0x08 #define DRM_NOUVEAU_MEM_FREE 0x09 +#define DRM_NOUVEAU_MEM_TILE 0x0a #endif /* __NOUVEAU_DRM_H__ */ diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 1aaf1d74..cd5f9cf8 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -34,7 +34,7 @@ #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 10 +#define DRIVER_PATCHLEVEL 11 #define NOUVEAU_FAMILY 0x0000FFFF #define NOUVEAU_FLAGS 0xFFFF0000 @@ -359,6 +359,8 @@ extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, struct drm_file *); extern int nouveau_ioctl_mem_free(struct drm_device *, void *data, struct drm_file *); +extern int nouveau_ioctl_mem_tile(struct drm_device *, void *data, + struct drm_file *); extern struct mem_block* nouveau_mem_alloc(struct drm_device *, int alignment, uint64_t size, int flags, struct drm_file *); diff --git a/shared-core/nouveau_fifo.c b/shared-core/nouveau_fifo.c index d8fda277..085336af 100644 --- a/shared-core/nouveau_fifo.c +++ b/shared-core/nouveau_fifo.c @@ -593,6 +593,7 @@ struct drm_ioctl_desc nouveau_ioctls[] = { DRM_IOCTL_DEF(DRM_NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_ALLOC, nouveau_ioctl_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_FREE, nouveau_ioctl_mem_free, DRM_AUTH), + DRM_IOCTL_DEF(DRM_NOUVEAU_MEM_TILE, nouveau_ioctl_mem_tile, DRM_AUTH), }; int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 58942829..d79c1a52 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -594,7 +594,7 @@ nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, * page size in the GPU VM. */ if (flags & NOUVEAU_MEM_FB && dev_priv->card_type >= NV_50) { - size = (size + (64 * 1024)) & ~((64 * 1024) - 1); + size = (size + 65535) & ~65535; if (alignment < 16) alignment = 16; } @@ -659,6 +659,7 @@ alloc_ok: struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt; unsigned offset = block->start; unsigned count = block->size / 65536; + unsigned tile = 0; if (!pt) { DRM_ERROR("vm alloc without vm pt\n"); @@ -666,11 +667,22 @@ alloc_ok: return NULL; } + /* The tiling stuff is *not* what NVIDIA does - but both the + * 2D and 3D engines seem happy with this simpler method. + * Should look into why NVIDIA do what they do at some point. + */ + if (flags & NOUVEAU_MEM_TILE) { + if (flags & NOUVEAU_MEM_TILE_ZETA) + tile = 0x00002800; + else + tile = 0x00007000; + } + while (count--) { unsigned pte = offset / 65536; INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); - INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000); + INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile); offset += 65536; } } else { @@ -808,3 +820,53 @@ nouveau_ioctl_mem_free(struct drm_device *dev, void *data, nouveau_mem_free(dev, block); return 0; } + +int +nouveau_ioctl_mem_tile(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_mem_tile *memtile = data; + struct mem_block *block = NULL; + + NOUVEAU_CHECK_INITIALISED_WITH_RETURN; + + if (dev_priv->card_type < NV_50) + return -EINVAL; + + if (memtile->flags & NOUVEAU_MEM_FB) { + memtile->offset -= 512*1024*1024; + block = find_block(dev_priv->fb_heap, memtile->offset); + } + + if (!block) + return -EINVAL; + + if (block->file_priv != file_priv) + return -EPERM; + + { + struct nouveau_gpuobj *pt = dev_priv->vm_vram_pt; + unsigned offset = block->start + memtile->delta; + unsigned count = memtile->size / 65536; + unsigned tile = 0; + + if (memtile->flags & NOUVEAU_MEM_TILE) { + if (memtile->flags & NOUVEAU_MEM_TILE_ZETA) + tile = 0x00002800; + else + tile = 0x00007000; + } + + while (count--) { + unsigned pte = offset / 65536; + + INSTANCE_WR(pt, (pte * 2) + 0, offset | 1); + INSTANCE_WR(pt, (pte * 2) + 1, 0x00000000 | tile); + offset += 65536; + } + } + + return 0; +} + -- cgit v1.2.3 From eac0933be75b226e0b623d8dcbf343c391eb88a2 Mon Sep 17 00:00:00 2001 From: martin capitanio Date: Tue, 8 Jul 2008 17:58:10 +1000 Subject: xgi: use true/false instead of TRUE/FALSE --- linux-core/xgi_cmdlist.c | 6 +++--- linux-core/xgi_drv.c | 4 ++-- linux-core/xgi_misc.c | 26 +++++++++++++------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/linux-core/xgi_cmdlist.c b/linux-core/xgi_cmdlist.c index e433c21d..423208b0 100644 --- a/linux-core/xgi_cmdlist.c +++ b/linux-core/xgi_cmdlist.c @@ -135,7 +135,7 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data, DRM_DEBUG("info->cmdring.last_ptr != NULL\n"); if (pCmdInfo->type == BTYPE_3D) { - xgi_emit_flush(info, FALSE); + xgi_emit_flush(info, false); } info->cmdring.last_ptr[1] = cpu_to_le32(begin[1]); @@ -216,7 +216,7 @@ void xgi_cmdlist_cleanup(struct xgi_info * info) * list chain with a flush command. */ if (info->cmdring.last_ptr != NULL) { - xgi_emit_flush(info, FALSE); + xgi_emit_flush(info, false); xgi_emit_nop(info); } @@ -324,5 +324,5 @@ void xgi_emit_irq(struct xgi_info * info) if (info->cmdring.last_ptr == NULL) return; - xgi_emit_flush(info, TRUE); + xgi_emit_flush(info, true); } diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 532408db..bfe9acdf 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -314,8 +314,8 @@ void xgi_driver_lastclose(struct drm_device * dev) || info->pcie_heap_initialized) { drm_sman_cleanup(&info->sman); - info->fb_heap_initialized = FALSE; - info->pcie_heap_initialized = FALSE; + info->fb_heap_initialized = false; + info->pcie_heap_initialized = false; } } } diff --git a/linux-core/xgi_misc.c b/linux-core/xgi_misc.c index 2b3a1788..2a9632f6 100644 --- a/linux-core/xgi_misc.c +++ b/linux-core/xgi_misc.c @@ -46,41 +46,41 @@ static bool xgi_validate_signal(struct drm_map * map) check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x3f) != ((check & 0x3f00) >> 8)) { - return FALSE; + return false; } /* Check RO channel */ DRM_WRITE8(map, 0x235c, 0x83); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x0f) != ((check & 0xf0) >> 4)) { - return FALSE; + return false; } /* Check RW channel */ DRM_WRITE8(map, 0x235c, 0x88); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if ((check & 0x0f) != ((check & 0xf0) >> 4)) { - return FALSE; + return false; } /* Check RO channel outstanding */ DRM_WRITE8(map, 0x235c, 0x8f); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if (0 != (check & 0x3ff)) { - return FALSE; + return false; } /* Check RW channel outstanding */ DRM_WRITE8(map, 0x235c, 0x90); check = le16_to_cpu(DRM_READ16(map, 0x2360)); if (0 != (check & 0x3ff)) { - return FALSE; + return false; } /* No pending PCIE request. GE stall. */ } - return TRUE; + return true; } @@ -138,7 +138,7 @@ static void xgi_ge_hang_reset(struct drm_map * map) bool xgi_ge_irq_handler(struct xgi_info * info) { const u32 int_status = le32_to_cpu(DRM_READ32(info->mmio_map, 0x2810)); - bool is_support_auto_reset = FALSE; + bool is_support_auto_reset = false; /* Check GE on/off */ if (0 == (0xffffc0f0 & int_status)) { @@ -179,15 +179,15 @@ bool xgi_ge_irq_handler(struct xgi_info * info) cpu_to_le32((int_status & ~0x01) | 0x04000000)); } - return TRUE; + return true; } - return FALSE; + return false; } bool xgi_crt_irq_handler(struct xgi_info * info) { - bool ret = FALSE; + bool ret = false; u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); /* CRT1 interrupt just happened @@ -205,7 +205,7 @@ bool xgi_crt_irq_handler(struct xgi_info * info) op3cf_3d = IN3CFB(info->mmio_map, 0x3d); OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d | 0x04)); OUT3CFB(info->mmio_map, 0x3d, (op3cf_3d & ~0x04)); - ret = TRUE; + ret = true; } DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); @@ -214,7 +214,7 @@ bool xgi_crt_irq_handler(struct xgi_info * info) bool xgi_dvi_irq_handler(struct xgi_info * info) { - bool ret = FALSE; + bool ret = false; const u8 save_3ce = DRM_READ8(info->mmio_map, 0x3ce); /* DVI interrupt just happened @@ -242,7 +242,7 @@ bool xgi_dvi_irq_handler(struct xgi_info * info) OUT3C5B(info->mmio_map, 0x39, (op3cf_39 & ~0x01)); OUT3C5B(info->mmio_map, 0x39, (op3cf_39 | 0x01)); - ret = TRUE; + ret = true; } DRM_WRITE8(info->mmio_map, 0x3ce, save_3ce); -- cgit v1.2.3 From 76c8e19a29d635d2c62937a381ab33014cfe6cea Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 15 Jul 2008 16:18:04 +1000 Subject: drm/pcigart: fix warning --- linux-core/ati_pcigart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index fb663a0a..40f8f8dd 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -126,7 +126,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga struct drm_sg_mem *entry = dev->sg; void *address = NULL; unsigned long pages; - u32 *pci_gart, page_base; + u32 *pci_gart; dma_addr_t bus_address = 0; int i, j, ret = 0; int max_pages; -- cgit v1.2.3 From abdd523c759a5e19e733e3b544c2f1bcaa7a0b9a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 15 Jul 2008 16:18:22 +1000 Subject: drm: add fix for PAT on radeon with 2.6.26 --- linux-core/drmP.h | 1 + linux-core/drm_compat.h | 4 ++++ linux-core/drm_memory.c | 8 ++++++++ shared-core/radeon_cp.c | 2 +- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 00db3000..331f3ac5 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1255,6 +1255,7 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) } extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); +extern void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev); extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 30834f33..3339219d 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -362,4 +362,8 @@ extern struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, unsigned long address, int *type); #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)) +#define drm_core_ioremap_wc drm_core_ioremap +#endif + #endif diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 75f5b521..6af73c8d 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -348,6 +348,14 @@ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) } EXPORT_SYMBOL_GPL(drm_core_ioremap); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev) +{ + map->handle = ioremap_wc(map->offset, map->size); +} +#endif + void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) { if (!map->handle || !map->size) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 9b1ea855..9bfda005 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1158,7 +1158,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) dev_priv->gart_info.mapping.size = dev_priv->gart_info.table_size; - drm_core_ioremap(&dev_priv->gart_info.mapping, dev); + drm_core_ioremap_wc(&dev_priv->gart_info.mapping, dev); dev_priv->gart_info.addr = dev_priv->gart_info.mapping.handle; -- cgit v1.2.3 From 764573f3b8bec90f20c3bdd58c4b55490fbbdaf4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 15 Jul 2008 20:27:14 +1000 Subject: drm: fix missing symbol export --- linux-core/drm_memory.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 6af73c8d..e1df3dac 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -354,6 +354,7 @@ void drm_core_ioremap_wc(struct drm_map *map, struct drm_device *dev) { map->handle = ioremap_wc(map->offset, map->size); } +EXPORT_SYMBOL_GPL(drm_core_ioremap_wc); #endif void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) -- cgit v1.2.3 From dfd441cf964f20e4a761cb8490d7cd82cf32e7b9 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Tue, 15 Jul 2008 10:14:17 -0700 Subject: This is a modified version of Hong's patch from last month, with a few modifications to make it work correctly on my test hardware (altered the backlight write function, made it enable the legacy backlight controller interrupts on mobile hardware, sorted the interrupt function so we don't get an excessive number of vblank interrupts). This lets the backlight keys on my T61 work properly, though there's a 750msec or so delay between the request and the brightness actually changing - this sounds awfully like the hardware spinning waiting for a status flag to become ready, but as far as I can tell they're all set correctly. If anyone can figure out what's wrong here, it'd be nice to know. Some of the functions are still stubs and just tell the hardware that the request was successful. These can be filled in as kernel modesetting gets integrated. I think it's worth getting this in anyway, since it's required for backlight control to work properly on some new platforms. Signed-off-by: Matthew Garrett --- linux-core/Makefile.kernel | 3 +- linux-core/i915_drv.c | 4 + linux-core/i915_opregion.c | 386 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_dma.c | 5 + shared-core/i915_drv.h | 30 ++++ shared-core/i915_irq.c | 22 +++ 6 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 linux-core/i915_opregion.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b9f078dd..45a6b1f9 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -20,7 +20,8 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ - i915_buffer.o i915_compat.o i915_execbuf.o i915_suspend.o + i915_buffer.o i915_compat.o i915_execbuf.o i915_suspend.o \ + i915_opregion.o nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \ nouveau_sgdma.o nouveau_dma.o nouveau_bo.o nouveau_fence.o \ diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index be25239d..abb45de7 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -80,6 +80,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state) i915_save_state(dev); + intel_opregion_free(dev); + if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ pci_disable_device(dev->pdev); @@ -99,6 +101,8 @@ static int i915_resume(struct drm_device *dev) i915_restore_state(dev); + intel_opregion_init(dev); + return 0; } diff --git a/linux-core/i915_opregion.c b/linux-core/i915_opregion.c new file mode 100644 index 00000000..e691571a --- /dev/null +++ b/linux-core/i915_opregion.c @@ -0,0 +1,386 @@ +/* + * + * Copyright 2008 Intel Corporation + * Copyright 2008 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include "drmP.h" +#include "i915_drm.h" +#include "i915_drv.h" + +#define PCI_ASLE 0xe4 +#define PCI_ASLS 0xfc + +#define OPREGION_SZ (8*1024) +#define OPREGION_HEADER_OFFSET 0 +#define OPREGION_ACPI_OFFSET 0x100 +#define OPREGION_SWSCI_OFFSET 0x200 +#define OPREGION_ASLE_OFFSET 0x300 +#define OPREGION_VBT_OFFSET 0x1000 + +#define OPREGION_SIGNATURE "IntelGraphicsMem" +#define MBOX_ACPI (1<<0) +#define MBOX_SWSCI (1<<1) +#define MBOX_ASLE (1<<2) + +/* _DOD id definitions */ +#define OUTPUT_CONNECTOR_MSK 0xf000 +#define OUTPUT_CONNECTOR_OFFSET 12 + +#define OUTPUT_PORT_MSK 0x00f0 +#define OUTPUT_PORT_OFFSET 4 + #define OUTPUT_PORT_ANALOG 0 + #define OUTPUT_PORT_LVDS 1 + #define OUTPUT_PORT_SDVOB 2 + #define OUTPUT_PORT_SDVOC 3 + #define OUTPUT_PORT_TV 4 + +#define OUTPUT_DISPLAY_MSK 0x0f00 +#define OUTPUT_DISPLAY_OFFSET 8 + #define OUTPUT_DISPLAY_OTHER 0 + #define OUTPUT_DISPLAY_VGA 1 + #define OUTPUT_DISPLAY_TV 2 + #define OUTPUT_DISPLAY_DIGI 3 + #define OUTPUT_DISPLAY_FLAT_PANEL 4 + +/* predefined id for integrated LVDS and VGA connector */ +#define OUTPUT_INT_LVDS 0x00000110 +#define OUTPUT_INT_VGA 0x80000100 + +struct opregion_header { + u8 signature[16]; + u32 size; + u32 opregion_ver; + u8 bios_ver[32]; + u8 vbios_ver[16]; + u8 driver_ver[16]; + u32 mboxes; + u8 reserved[164]; +} __attribute__((packed)); + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi { + u32 drdy; /* driver readiness */ + u32 csts; /* notification status */ + u32 cevt; /* current event */ + u8 rsvd1[20]; + u32 didl[8]; /* supported display devices ID list */ + u32 cpdl[8]; /* currently presented display list */ + u32 cadl[8]; /* currently active display list */ + u32 nadl[8]; /* next active devices list */ + u32 aslp; /* ASL sleep time-out */ + u32 tidx; /* toggle table index */ + u32 chpd; /* current hotplug enable indicator */ + u32 clid; /* current lid state*/ + u32 cdck; /* current docking state */ + u32 sxsw; /* Sx state resume */ + u32 evts; /* ASL supported events */ + u32 cnot; /* current OS notification */ + u32 nrdy; /* driver status */ + u8 rsvd2[60]; +} __attribute__((packed)); + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci { + u32 scic; /* SWSCI command|status|data */ + u32 parm; /* command parameters */ + u32 dslp; /* driver sleep time-out */ + u8 rsvd[244]; +} __attribute__((packed)); + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle { + u32 ardy; /* driver readiness */ + u32 aslc; /* ASLE interrupt command */ + u32 tche; /* technology enabled indicator */ + u32 alsi; /* current ALS illuminance reading */ + u32 bclp; /* backlight brightness to set */ + u32 pfit; /* panel fitting state */ + u32 cblv; /* current brightness level */ + u16 bclm[20]; /* backlight level duty cycle mapping table */ + u32 cpfm; /* current panel fitting mode */ + u32 epfm; /* enabled panel fitting modes */ + u8 plut[74]; /* panel LUT and identifier */ + u32 pfmb; /* PWM freq and min brightness */ + u8 rsvd[102]; +} __attribute__((packed)); + +/* ASLE irq request bits */ +#define ASLE_SET_ALS_ILLUM (1 << 0) +#define ASLE_SET_BACKLIGHT (1 << 1) +#define ASLE_SET_PFIT (1 << 2) +#define ASLE_SET_PWM_FREQ (1 << 3) +#define ASLE_REQ_MSK 0xf + +/* response bits of ASLE irq request */ +#define ASLE_ALS_ILLUM_FAIL (2<<10) +#define ASLE_BACKLIGHT_FAIL (2<<12) +#define ASLE_PFIT_FAIL (2<<14) +#define ASLE_PWM_FREQ_FAIL (2<<16) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID (1<<31) +#define ASLE_BCLP_MSK (~(1<<31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID (1<<31) +#define ASLE_PFIT_CENTER (1<<0) +#define ASLE_PFIT_STRETCH_TEXT (1<<1) +#define ASLE_PFIT_STRETCH_GFX (1<<2) + +/* PWM frequency and minimum brightness */ +#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) +#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8) +#define ASLE_PFMB_PWM_MASK (0x7ffffe00) +#define ASLE_PFMB_PWM_VALID (1<<31) + +#define ASLE_CBLV_VALID (1<<31) + +static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 blc_pwm_ctl; + + if (!(bclp & ASLE_BCLP_VALID)) + return ASLE_BACKLIGHT_FAIL; + + bclp &= ASLE_BCLP_MSK; + if (bclp < 0 || bclp > 255) + return ASLE_BACKLIGHT_FAIL; + + blc_pwm_ctl = I915_READ(BLC_PWM_CTL); + blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK; + I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | ((bclp * 0x101) -1)); + asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID; + + return 0; +} + +static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi) +{ + return 0; +} + +static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + if (pfmb & ASLE_PFMB_PWM_VALID) { + u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL); + u32 pwm = pfmb & ASLE_PFMB_PWM_MASK; + blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK; + pwm = pwm >> 9; + // FIXME - what do we do with the PWM? + } + return 0; +} + +static u32 asle_set_pfit(struct drm_device *dev, u32 pfit) +{ + if (!(pfit & ASLE_PFIT_VALID)) + return ASLE_PFIT_FAIL; + return 0; +} + +void opregion_asle_intr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + u32 asle_stat = 0; + u32 asle_req; + + if (!asle) + return; + + asle_req = asle->aslc & ASLE_REQ_MSK; + + if (!asle_req) { + DRM_DEBUG("non asle set request??\n"); + return; + } + + if (asle_req & ASLE_SET_ALS_ILLUM) + asle_stat |= asle_set_als_illum(dev, asle->alsi); + + if (asle_req & ASLE_SET_BACKLIGHT) + asle_stat |= asle_set_backlight(dev, asle->bclp); + + if (asle_req & ASLE_SET_PFIT) + asle_stat |= asle_set_pfit(dev, asle->pfit); + + if (asle_req & ASLE_SET_PWM_FREQ) + asle_stat |= asle_set_pwm_freq(dev, asle->pfmb); + + asle->aslc = asle_stat; +} + +#define ASLE_ALS_EN (1<<0) +#define ASLE_BLC_EN (1<<1) +#define ASLE_PFIT_EN (1<<2) +#define ASLE_PFMB_EN (1<<3) + +void opregion_enable_asle(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct opregion_asle *asle = dev_priv->opregion.asle; + + if (asle) { + u32 pipeb_stats = I915_READ(PIPEBSTAT); + if (IS_MOBILE(dev)) { + /* Some hardware uses the legacy backlight controller + to signal interrupts, so we need to set up pipe B + to generate an IRQ on writes */ + I915_WRITE(PIPEBSTAT, pipeb_stats |= + I915_LEGACY_BLC_EVENT_ENABLE); + dev_priv->irq_enable_reg |= + (I915_ASLE_INTERRUPT + | I915_DISPLAY_PIPE_B_EVENT_INTERRUPT); + } else + dev_priv->irq_enable_reg |= I915_ASLE_INTERRUPT; + + asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN | + ASLE_PFMB_EN; + asle->ardy = 1; + } +} + +#define ACPI_EV_DISPLAY_SWITCH (1<<0) +#define ACPI_EV_LID (1<<1) +#define ACPI_EV_DOCK (1<<2) + +static struct intel_opregion *system_opregion; + +int intel_opregion_video_event(struct notifier_block *nb, unsigned long val, + void *data) +{ + /* The only video events relevant to opregion are 0x80. These indicate + either a docking event, lid switch or display switch request. In + Linux, these are handled by the dock, button and video drivers. + We might want to fix the video driver to be opregion-aware in + future, but right now we just indicate to the firmware that the + request has been handled */ + + struct opregion_acpi *acpi; + + if (!system_opregion) + return NOTIFY_DONE; + + acpi = system_opregion->acpi; + acpi->csts = 0; + + return NOTIFY_OK; +} + +static struct notifier_block intel_opregion_notifier = { + .notifier_call = intel_opregion_video_event, +}; + +int intel_opregion_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + void *base; + u32 asls, mboxes; + int err = 0; + + pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); + DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls); + if (asls == 0) { + DRM_DEBUG("ACPI OpRegion not supported!\n"); + return -ENOTSUPP; + } + + base = ioremap(asls, OPREGION_SZ); + if (!base) + return -ENOMEM; + + opregion->header = base; + if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) { + DRM_DEBUG("opregion signature mismatch\n"); + err = -EINVAL; + goto err_out; + } + + mboxes = opregion->header->mboxes; + if (mboxes & MBOX_ACPI) { + DRM_DEBUG("Public ACPI methods supported\n"); + opregion->acpi = base + OPREGION_ACPI_OFFSET; + } else { + DRM_DEBUG("Public ACPI methods not supported\n"); + err = -ENOTSUPP; + goto err_out; + } + opregion->enabled = 1; + + if (mboxes & MBOX_SWSCI) { + DRM_DEBUG("SWSCI supported\n"); + opregion->swsci = base + OPREGION_SWSCI_OFFSET; + } + if (mboxes & MBOX_ASLE) { + DRM_DEBUG("ASLE supported\n"); + opregion->asle = base + OPREGION_ASLE_OFFSET; + } + + /* Notify BIOS we are ready to handle ACPI video ext notifs. + * Right now, all the events are handled by the ACPI video module. + * We don't actually need to do anything with them. */ + opregion->acpi->csts = 0; + opregion->acpi->drdy = 1; + + system_opregion = opregion; + register_acpi_notifier(&intel_opregion_notifier); + + return 0; + +err_out: + iounmap(opregion->header); + opregion->header = NULL; + return err; +} + +void intel_opregion_free(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_opregion *opregion = &dev_priv->opregion; + + if (!opregion->enabled) + return; + + opregion->acpi->drdy = 0; + + system_opregion = NULL; + unregister_acpi_notifier(&intel_opregion_notifier); + + /* just clear all opregion memory pointers now */ + iounmap(opregion->header); + opregion->header = NULL; + opregion->acpi = NULL; + opregion->swsci = NULL; + opregion->asle = NULL; + + opregion->enabled = 0; +} diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 27d152cb..ad6e1293 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1038,6 +1038,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) intel_init_chipset_flush_compat(dev); #endif + intel_opregion_init(dev); #endif return ret; @@ -1050,6 +1051,10 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mmio_map) drm_rmmap(dev, dev_priv->mmio_map); +#ifdef __linux__ + intel_opregion_free(dev); +#endif + drm_free(dev->dev_private, sizeof(drm_i915_private_t), DRM_MEM_DRIVER); #ifdef __linux__ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index fa3305ba..421572cd 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -105,6 +105,22 @@ typedef struct _drm_i915_vbl_swap { int flip; } drm_i915_vbl_swap_t; +#ifdef __linux__ +struct opregion_header; +struct opregion_acpi; +struct opregion_swsci; +struct opregion_asle; + +struct intel_opregion { + struct opregion_header *header; + struct opregion_acpi *acpi; + struct opregion_swsci *swsci; + struct opregion_asle *asle; + + int enabled; +}; +#endif + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -158,6 +174,11 @@ typedef struct drm_i915_private { struct drm_buffer_object *sarea_bo; struct drm_bo_kmap_obj sarea_kmap; #endif + +#ifdef __linux__ + struct intel_opregion opregion; +#endif + /* Register state */ u8 saveLBB; u32 saveDSPACNTR; @@ -342,6 +363,14 @@ int i915_execbuffer(struct drm_device *dev, void *data, #endif +#ifdef __linux__ +/* i915_opregion.c */ +extern int intel_opregion_init(struct drm_device *dev); +extern void intel_opregion_free(struct drm_device *dev); +extern void opregion_asle_intr(struct drm_device *dev); +extern void opregion_enable_asle(struct drm_device *dev); +#endif + #ifdef __linux__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) extern void intel_init_chipset_flush_compat(struct drm_device *dev); @@ -613,6 +642,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4) #define I915_DEBUG_INTERRUPT (1<<2) #define I915_USER_INTERRUPT (1<<1) +#define I915_ASLE_INTERRUPT (1<<0) #define EIR 0x020b0 #define EMR 0x020b4 #define ESR 0x020b8 diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 28f9f6af..d7fa47d3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -474,15 +474,33 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) { pipeb_stats = I915_READ(PIPEBSTAT); + /* Ack the event */ + I915_WRITE(PIPEBSTAT, pipeb_stats); + + /* The vblank interrupt gets enabled even if we didn't ask for + it, so make sure it's shut down again */ + if (!(dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)) + pipeb_stats &= ~(I915_VBLANK_INTERRUPT_ENABLE); + if (pipeb_stats & (PIPE_START_VBLANK_INTERRUPT_STATUS| PIPE_VBLANK_INTERRUPT_STATUS)) { vblank++; drm_handle_vblank(dev, i915_get_plane(dev, 1)); } + +#ifdef __linux__ + if (pipeb_stats & I915_LEGACY_BLC_EVENT_ENABLE) + opregion_asle_intr(dev); +#endif I915_WRITE(PIPEBSTAT, pipeb_stats); } +#ifdef __linux__ + if (iir & I915_ASLE_INTERRUPT) + opregion_asle_intr(dev); +#endif + if (dev_priv->sarea_priv) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -703,6 +721,10 @@ static void i915_enable_interrupt (struct drm_device *dev) dev_priv->irq_enable_reg |= I915_USER_INTERRUPT; +#ifdef __linux__ + opregion_enable_asle(dev); +#endif + I915_WRITE(IER, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; } -- cgit v1.2.3 From 96580f660e5509dcf6c34de5630e3d36b156bcd5 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 9 Jun 2008 08:54:53 -0400 Subject: [FreeBSD] We aren't allowed to hold locks over bus_dma_tag_create or bus_dmamem_alloc. --- bsd-core/drm_pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bsd-core/drm_pci.c b/bsd-core/drm_pci.c index 6b411abb..f23b2a5b 100644 --- a/bsd-core/drm_pci.c +++ b/bsd-core/drm_pci.c @@ -71,6 +71,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size, return NULL; #ifdef __FreeBSD__ + DRM_UNLOCK(); ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */ maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ NULL, NULL, /* filtfunc, filtfuncargs */ @@ -79,6 +80,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size, &dmah->tag); if (ret != 0) { free(dmah, M_DRM); + DRM_LOCK(); return NULL; } @@ -87,9 +89,10 @@ drm_pci_alloc(struct drm_device *dev, size_t size, if (ret != 0) { bus_dma_tag_destroy(dmah->tag); free(dmah, M_DRM); + DRM_LOCK(); return NULL; } - + DRM_LOCK(); ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size, drm_pci_busdma_callback, dmah, 0); if (ret != 0) { -- cgit v1.2.3 From 74cf1f91be7f4139601624af0343e3d411190dec Mon Sep 17 00:00:00 2001 From: Owain Gordon Ainsworth Date: Mon, 7 Jul 2008 17:23:48 +0100 Subject: BSD: change drm_locked_task*() to use the same scheme as linux. The current code can sleep in an interrupt handler, that is bad. So instead if we can't grab the lock, flag it and run the tasklet on unlock. Signed-off-by: Robert Noland --- bsd-core/drmP.h | 1 + bsd-core/drm_drv.c | 1 + bsd-core/drm_irq.c | 45 +++++++++++++++++++++++---------------------- bsd-core/drm_lock.c | 7 +++++++ 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 88ea4e69..65d7fae4 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -739,6 +739,7 @@ struct drm_device { struct mtx dev_lock; /* protects everything else */ #endif DRM_SPINTYPE drw_lock; + DRM_SPINTYPE tsk_lock; /* Usage Counters */ int open_count; /* Outstanding files open */ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 740a8b57..9bd6079f 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -206,6 +206,7 @@ int drm_attach(device_t nbdev, drm_pci_id_list_t *idlist) mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); + mtx_init(&dev->tsk_lock, "drmtsk", NULL, MTX_DEF); #endif id_entry = drm_find_description(pci_get_vendor(dev->device), diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index c3ecd28b..a066cfc9 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -578,41 +578,42 @@ static void drm_locked_task(void *context, int pending __unused) { struct drm_device *dev = context; - DRM_LOCK(); - for (;;) { - int ret; - - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) - { - dev->lock.file_priv = NULL; /* kernel owned */ - dev->lock.lock_time = jiffies; - atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } + DRM_SPINLOCK(&dev->tsk_lock); - /* Contention */ -#if defined(__FreeBSD__) && __FreeBSD_version > 500000 - ret = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock, - PZERO | PCATCH, "drmlk2", 0); -#else - ret = tsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH, - "drmlk2", 0); -#endif - if (ret != 0) - return; + DRM_LOCK(); /* XXX drm_lock_take() should do it's own locking */ + if (dev->locked_task_call == NULL || + drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT) == 0) { + DRM_UNLOCK(); + DRM_SPINUNLOCK(&dev->tsk_lock); + return; } + + dev->lock.file_priv = NULL; /* kernel owned */ + dev->lock.lock_time = jiffies; + atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); + DRM_UNLOCK(); dev->locked_task_call(dev); drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); + + dev->locked_task_call = NULL; + + DRM_SPINUNLOCK(&dev->tsk_lock); } void drm_locked_tasklet(struct drm_device *dev, void (*tasklet)(struct drm_device *dev)) { + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + DRM_SPINUNLOCK(&dev->tsk_lock); + return; + } + dev->locked_task_call = tasklet; + DRM_SPINUNLOCK(&dev->tsk_lock); taskqueue_enqueue(taskqueue_swi, &dev->locked_task); } diff --git a/bsd-core/drm_lock.c b/bsd-core/drm_lock.c index 9101dec8..80ebb71d 100644 --- a/bsd-core/drm_lock.c +++ b/bsd-core/drm_lock.c @@ -180,6 +180,13 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) != lock->context) return EINVAL; + DRM_SPINLOCK(&dev->tsk_lock); + if (dev->locked_task_call != NULL) { + dev->locked_task_call(dev); + dev->locked_task_call = NULL; + } + DRM_SPINUNLOCK(&dev->tsk_lock); + atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); DRM_LOCK(); -- cgit v1.2.3 From b0e4619a396f2db8c594cd0a26fd2f0ab9358095 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Wed, 16 Jul 2008 23:39:25 -0400 Subject: FreeBSD: Fix radeon build --- bsd-core/drmP.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 65d7fae4..b0a23e9c 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -1088,6 +1088,8 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, dma_addr_t maxaddr); void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); +#define drm_core_ioremap_wc drm_core_ioremap + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) -- cgit v1.2.3 From 2204f926abe4da87a38955c4ecf9adb73b646666 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 17 Jul 2008 13:48:14 -0400 Subject: Avoid incorrect vblank wakeups The current code uses the hw vblank counter exclusively, which can lead to wakeups during the active period rather than during the vblank period if the hw counter counts displayed frames rather than vblank periods. This change coverts the code over to using the counter while interrupts are enabled, fixing that issue. It also includes a couple of related changes: one to not enable the new enable/disable behavior until the modeset ioctl is called (to preserve old client behavior) and another to account for lost events due to mode setting with the new counter scheme. BSD will require similar changes to its drm_irq.c code, but they should be straightforward. --- linux-core/drmP.h | 8 ++++++ linux-core/drm_irq.c | 74 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 331f3ac5..45a599b4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -832,6 +832,14 @@ struct drm_device { /** \name VBLANK IRQ support */ /*@{ */ + /* + * At load time, disabling the vblank interrupt won't be allowed since + * old clients may not call the modeset ioctl and therefore misbehave. + * Once the modeset ioctl *has* been called though, we can safely + * disable them when unused. + */ + int vblank_disable_allowed; + wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ spinlock_t vbl_lock; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index abedbe73..75e53da9 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -77,10 +77,16 @@ static void vblank_disable_fn(unsigned long arg) unsigned long irqflags; int i; + if (!dev->vblank_disable_allowed) + return; + for (i = 0; i < dev->num_crtcs; i++) { spin_lock_irqsave(&dev->vbl_lock, irqflags); if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { + DRM_DEBUG("disabling vblank on crtc %d\n", i); + dev->last_vblank[i] = + dev->driver->get_vblank_counter(dev, i); dev->driver->disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } @@ -175,6 +181,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) atomic_set(&dev->vblank_refcount[i], 0); } + dev->vblank_disable_allowed = 0; + return 0; err: @@ -344,10 +352,15 @@ EXPORT_SYMBOL(drm_vblank_count); * (specified by @crtc). Deal with wraparound, if it occurred, and * update the last read value so we can deal with wraparound on the next * call if necessary. + * + * Only necessary when going from off->on, to account for frames we + * didn't get an interrupt for. + * + * Note: caller must hold dev->vbl_lock since this reads & writes + * device vblank fields. */ void drm_update_vblank_count(struct drm_device *dev, int crtc) { - unsigned long irqflags; u32 cur_vblank, diff; if (dev->vblank_suspend[crtc]) @@ -361,7 +374,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver->get_vblank_counter(dev, crtc); - spin_lock_irqsave(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { if (cur_vblank == dev->last_vblank[crtc] - 1) { diff = 0; @@ -377,11 +389,12 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + crtc, diff); atomic_add(diff, &dev->_vblank_count[crtc]); } -EXPORT_SYMBOL(drm_update_vblank_count); /** * drm_vblank_get - get a reference count on vblank events @@ -389,9 +402,7 @@ EXPORT_SYMBOL(drm_update_vblank_count); * @crtc: which CRTC to own * * Acquire a reference count on vblank events to avoid having them disabled - * while in use. Note callers will probably want to update the master counter - * using drm_update_vblank_count() above before calling this routine so that - * wakeups occur on the right vblank event. + * while in use. * * RETURNS * Zero on success, nonzero on failure. @@ -408,8 +419,10 @@ int drm_vblank_get(struct drm_device *dev, int crtc) ret = dev->driver->enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else + else { dev->vblank_enabled[crtc] = 1; + drm_update_vblank_count(dev, crtc); + } } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -439,11 +452,18 @@ EXPORT_SYMBOL(drm_vblank_put); * * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET * ioctls around modesetting so that any lost vblank events are accounted for. + * + * Generally the counter will reset across mode sets. If interrupts are + * enabled around this call, we don't have to do anything since the counter + * will have already been incremented. If interrupts are off though, we need + * to make sure we account for the lost events at %_DRM_POST_MODESET time. */ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; + unsigned long irqflags; + u32 new, diff; int crtc, ret = 0; crtc = modeset->crtc; @@ -454,27 +474,28 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: - dev->vblank_premodeset[crtc] = - dev->driver->get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + spin_lock_irqsave(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + if (!dev->vblank_enabled[crtc]) { + dev->vblank_premodeset[crtc] = + dev->driver->get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { - u32 new = dev->driver->get_vblank_counter(dev, crtc); - - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) { - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); - DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" - " => _vblank_count[%d]-=0x%x\n", crtc, - dev->vblank_premodeset[crtc], new, - crtc, dev->max_vblank_count + new - - dev->vblank_premodeset[crtc]); - } + spin_lock_irqsave(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + new = dev->driver->get_vblank_counter(dev, crtc); + if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { + if (new > dev->vblank_premodeset[crtc]) + diff = dev->vblank_premodeset[crtc] - new; + else + diff = new; + atomic_add(diff, &dev->_vblank_count[crtc]); } dev->vblank_suspend[crtc] = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); break; default: ret = -EINVAL; @@ -528,7 +549,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (crtc >= dev->num_crtcs) return -EINVAL; - drm_update_vblank_count(dev, crtc); seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -680,7 +700,7 @@ static void drm_vbl_send_signals(struct drm_device * dev, int crtc) */ void drm_handle_vblank(struct drm_device *dev, int crtc) { - drm_update_vblank_count(dev, crtc); + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } -- cgit v1.2.3 From a9427cf31861542ff4f4d3db498e5f2ada7da4c1 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 17 Jul 2008 13:51:24 -0400 Subject: i915: remove old broken vblank code Remove the unused (and broken) "in vblank" code now that the core has been fixed to use a counter while interrupts are enabled. Also make the vblank pipe get/set ioctls into dumb stub functions, since with the new code we can no longer let userspace control whether vblank interrupts are enabled, or the core code will misbehave. --- shared-core/i915_irq.c | 70 ++++---------------------------------------------- 1 file changed, 5 insertions(+), 65 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d7fa47d3..ecb2d7fc 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -361,28 +361,7 @@ static void i915_vblank_tasklet(struct drm_device *dev) drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER); } } -#if 0 -static int i915_in_vblank(struct drm_device *dev, int pipe) -{ - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned long pipedsl, vblank, vtotal; - unsigned long vbl_start, vbl_end, cur_line; - - pipedsl = pipe ? PIPEBDSL : PIPEADSL; - vblank = pipe ? VBLANK_B : VBLANK_A; - vtotal = pipe ? VTOTAL_B : VTOTAL_A; - - vbl_start = I915_READ(vblank) & VBLANK_START_MASK; - vbl_end = (I915_READ(vblank) >> VBLANK_END_SHIFT) & VBLANK_END_MASK; - - cur_line = I915_READ(pipedsl); - - if (cur_line >= vbl_start) - return 1; - return 0; -} -#endif u32 i915_get_vblank_counter(struct drm_device *dev, int plane) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -416,22 +395,6 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane) count = (high1 << 8) | low; - /* - * If we're in the middle of the vblank period, the - * above regs won't have been updated yet, so return - * an incremented count to stay accurate - */ -#if 0 - if (i915_in_vblank(dev, pipe)) - count++; -#endif - /* count may be reset by other driver(e.g. 2D driver), - we have no way to know if it is wrapped or resetted - when count is zero. do a rough guess. - */ - if (count == 0 && dev->last_vblank[pipe] < dev->max_vblank_count/2) - dev->last_vblank[pipe] = 0; - return count; } @@ -444,18 +407,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) int vblank = 0; iir = I915_READ(IIR); -#if 0 - DRM_DEBUG("flag=%08x\n", iir); -#endif - if (iir == 0) { - DRM_DEBUG ("iir 0x%08x im 0x%08x ie 0x%08x pipea 0x%08x pipeb 0x%08x\n", - iir, - I915_READ(IMR), - I915_READ(IER), - I915_READ(PIPEASTAT), - I915_READ(PIPEBSTAT)); + if (iir == 0) return IRQ_NONE; - } /* * Clear the PIPE(A|B)STAT regs before the IIR otherwise @@ -735,20 +688,12 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = dev->dev_private; - drm_i915_vblank_pipe_t *pipe = data; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } - if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe); - return -EINVAL; - } - - dev_priv->vblank_pipe = pipe->pipe; - return 0; } @@ -757,20 +702,13 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data, { drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_pipe_t *pipe = data; - u16 flag; if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } - flag = I915_READ(IER); - - pipe->pipe = 0; - if (flag & I915_DISPLAY_PIPE_A_EVENT_INTERRUPT) - pipe->pipe |= DRM_I915_VBLANK_PIPE_A; - if (flag & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) - pipe->pipe |= DRM_I915_VBLANK_PIPE_B; + pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; return 0; } @@ -831,7 +769,6 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); - drm_update_vblank_count(dev, pipe); curseq = drm_vblank_count(dev, pipe); if (seqtype == _DRM_VBLANK_RELATIVE) @@ -957,6 +894,7 @@ int i915_driver_irq_postinstall(struct drm_device * dev) if (ret) return ret; + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ i915_enable_interrupt(dev); @@ -978,6 +916,8 @@ void i915_driver_irq_uninstall(struct drm_device * dev) if (!dev_priv) return; + dev_priv->vblank_pipe = 0; + dev_priv->irq_enabled = 0; I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(IMR, 0xffffffff); -- cgit v1.2.3 From 480c317a6ae634d777931eee54fadd2a50a2f650 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 17 Jul 2008 14:01:04 -0400 Subject: [FreeBSD] drm_irq.c updates for vblank fixes. --- bsd-core/drmP.h | 1 + bsd-core/drm_irq.c | 58 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index b0a23e9c..2f2ffb3c 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -787,6 +787,7 @@ struct drm_device { atomic_t context_flag; /* Context swapping flag */ int last_context; /* Last current context */ + int vblank_disable_allowed; wait_queue_head_t *vbl_queue; /* vblank wait queue */ atomic_t *_vblank_count; /* number of VBLANK interrupts */ /* (driver must alloc the right number of counters) */ diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index a066cfc9..4b515ad8 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -81,9 +81,15 @@ static void vblank_disable_fn(void *arg) } callout_deactivate(&dev->vblank_disable_timer); + if (!dev->vblank_disable_allowed) + return; + for (i = 0; i < dev->num_crtcs; i++) { if (atomic_read(&dev->vblank_refcount[i]) == 0 && dev->vblank_enabled[i]) { + DRM_DEBUG("disabling vblank on crtc %d\n", i); + dev->last_vblank[i] = + dev->driver.get_vblank_counter(dev, i); dev->driver.disable_vblank(dev, i); dev->vblank_enabled[i] = 0; } @@ -181,6 +187,8 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) atomic_set(&dev->vblank_refcount[i], 0); } + dev->vblank_disable_allowed = 0; + return 0; err: @@ -334,7 +342,6 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) void drm_update_vblank_count(struct drm_device *dev, int crtc) { - unsigned long irqflags; u32 cur_vblank, diff; if (dev->vblank_suspend[crtc]) @@ -348,7 +355,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); if (cur_vblank < dev->last_vblank[crtc]) { if (cur_vblank == dev->last_vblank[crtc] - 1) { diff = 0; @@ -364,7 +370,9 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) diff = cur_vblank - dev->last_vblank[crtc]; } dev->last_vblank[crtc] = cur_vblank; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + + DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", + crtc, diff); atomic_add(diff, &dev->_vblank_count[crtc]); } @@ -382,8 +390,10 @@ int drm_vblank_get(struct drm_device *dev, int crtc) ret = dev->driver.enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else + else { dev->vblank_enabled[crtc] = 1; + drm_update_vblank_count(dev, crtc); + } } DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); @@ -407,6 +417,8 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; + unsigned long irqflags; + u32 new, diff; int crtc, ret = 0; crtc = modeset->crtc; @@ -417,27 +429,28 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + if (!dev->vblank_enabled[crtc]) { + dev->vblank_premodeset[crtc] = + dev->driver.get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; + } + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { - u32 new = dev->driver.get_vblank_counter(dev, crtc); - - /* Compensate for spurious wraparound */ - if (new < dev->vblank_premodeset[crtc]) { - atomic_sub(dev->max_vblank_count + new - - dev->vblank_premodeset[crtc], - &dev->_vblank_count[crtc]); - DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" - " => _vblank_count[%d]-=0x%x\n", crtc, - dev->vblank_premodeset[crtc], new, - crtc, dev->max_vblank_count + new - - dev->vblank_premodeset[crtc]); - } + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + new = dev->driver.get_vblank_counter(dev, crtc); + if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { + if (new > dev->vblank_premodeset[crtc]) + diff = dev->vblank_premodeset[crtc] - new; + else + diff = new; + atomic_add(diff, &dev->_vblank_count[crtc]); } dev->vblank_suspend[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -471,7 +484,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (crtc >= dev->num_crtcs) return EINVAL; - drm_update_vblank_count(dev, crtc); seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -569,7 +581,7 @@ void drm_vbl_send_signals(struct drm_device *dev, int crtc ) void drm_handle_vblank(struct drm_device *dev, int crtc) { - drm_update_vblank_count(dev, crtc); + atomic_inc(&dev->_vblank_count[crtc]); DRM_WAKEUP(&dev->vbl_queue[crtc]); drm_vbl_send_signals(dev, crtc); } -- cgit v1.2.3 From ed7e1709158ca42736650379ee2aba64a827c51e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 19 Jun 2008 11:38:43 +1000 Subject: drm/radeon: fixup 0 vs NULL --- shared-core/radeon_mem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared-core/radeon_mem.c b/shared-core/radeon_mem.c index 1e582ee0..dbd73c50 100644 --- a/shared-core/radeon_mem.c +++ b/shared-core/radeon_mem.c @@ -88,7 +88,7 @@ static struct mem_block *alloc_block(struct mem_block *heap, int size, list_for_each(p, heap) { int start = (p->start + mask) & ~mask; - if (p->file_priv == 0 && start + size <= p->start + p->size) + if (p->file_priv == NULL && start + size <= p->start + p->size) return split_block(p, start, size, file_priv); } @@ -113,7 +113,7 @@ static void free_block(struct mem_block *p) /* Assumes a single contiguous range. Needs a special file_priv in * 'heap' to stop it being subsumed. */ - if (p->next->file_priv == 0) { + if (p->next->file_priv == NULL) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; @@ -121,7 +121,7 @@ static void free_block(struct mem_block *p) drm_free(q, sizeof(*q), DRM_MEM_BUFS); } - if (p->prev->file_priv == 0) { + if (p->prev->file_priv == NULL) { struct mem_block *q = p->prev; q->size += p->size; q->next = p->next; @@ -174,7 +174,7 @@ void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) * 'heap' to stop it being subsumed. */ list_for_each(p, heap) { - while (p->file_priv == 0 && p->next->file_priv == 0) { + while (p->file_priv == NULL && p->next->file_priv == NULL) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; -- cgit v1.2.3 From 7cfdba2b30e40efc688f1704bd4f4141dc6f9a6c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 18 Jul 2008 14:30:57 +1000 Subject: radeon: remove microcode version --- shared-core/radeon_cp.c | 15 ++------------- shared-core/radeon_drv.h | 9 +-------- shared-core/radeon_state.c | 30 ++++++++++++++++++------------ 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 9bfda005..ae31e969 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -893,17 +893,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) */ dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1; - switch(init->func) { - case RADEON_INIT_R200_CP: - dev_priv->microcode_version = UCODE_R200; - break; - case RADEON_INIT_R300_CP: - dev_priv->microcode_version = UCODE_R300; - break; - default: - dev_priv->microcode_version = UCODE_R100; - } - dev_priv->do_boxes = 0; dev_priv->cp_mode = init->cp_mode; @@ -951,8 +940,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) */ dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE | (dev_priv->color_fmt << 10) | - (dev_priv->microcode_version == - UCODE_R100 ? RADEON_ZBLOCK16 : 0)); + (dev_priv->chip_family < CHIP_R200 ? RADEON_ZBLOCK16 : 0)); dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt | @@ -1731,6 +1719,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) break; } + dev_priv->chip_family = flags & RADEON_FAMILY_MASK; if (drm_device_is_agp(dev)) dev_priv->flags |= RADEON_IS_AGP; else if (drm_device_is_pcie(dev)) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 9e7d9a99..9bd23be1 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -136,12 +136,6 @@ enum radeon_family { CHIP_LAST, }; -enum radeon_cp_microcode_version { - UCODE_R100, - UCODE_R200, - UCODE_R300, -}; - /* * Chip flags */ @@ -249,8 +243,6 @@ typedef struct drm_radeon_private { int usec_timeout; - int microcode_version; - struct { u32 boxes; int freelist_timeouts; @@ -321,6 +313,7 @@ typedef struct drm_radeon_private { int num_gb_pipes; int track_flush; + uint32_t chip_family; /* extract from flags */ } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index c50ac248..57e3a3bb 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -305,8 +305,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * case RADEON_CP_3D_DRAW_INDX_2: case RADEON_3D_CLEAR_HIZ: /* safe but r200 only */ - if (dev_priv->microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non r200-class chip\n"); return -EINVAL; } break; @@ -359,8 +360,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_3D_RNDR_GEN_INDX_PRIM: - if (dev_priv->microcode_version != UCODE_R100) { - DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + if (dev_priv->chip_family > CHIP_RS200) { + DRM_ERROR("Invalid 3d packet for non-r100-class chip\n"); return -EINVAL; } if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) { @@ -370,8 +371,10 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * break; case RADEON_CP_INDX_BUFFER: - if (dev_priv->microcode_version != UCODE_R200) { - DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + /* safe but r200 only */ + if ((dev_priv->chip_family < CHIP_R200) || + (dev_priv->chip_family > CHIP_RV280)) { + DRM_ERROR("Invalid 3d packet for non-r200-class chip\n"); return -EINVAL; } if ((cmd[1] & 0x8000ffff) != 0x80000810) { @@ -1015,7 +1018,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, int tileoffset, nrtilesx, nrtilesy, j; /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && !(dev_priv->microcode_version == UCODE_R200)) { + && (dev_priv->chip_family < CHIP_R200)) { /* FIXME : figure this out for r200 (when hierz is enabled). Or maybe r200 actually doesn't need to put the low-res z value into the tile cache like r100, but just needs to clear the hi-level z-buffer? @@ -1044,7 +1047,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, ADVANCE_RING(); tileoffset += depthpixperline >> 6; } - } else if (dev_priv->microcode_version == UCODE_R200) { + } else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) { /* works for rv250. */ /* find first macro tile (8x2 4x4 z-pixels on rv250) */ tileoffset = @@ -1099,7 +1103,8 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* TODO don't always clear all hi-level z tiles */ if ((dev_priv->flags & RADEON_HAS_HIERZ) - && (dev_priv->microcode_version == UCODE_R200) + && ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280)) && (flags & RADEON_USE_HIERZ)) /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ /* FIXME : the mask supposedly contains low-res z values. So can't set @@ -1119,8 +1124,9 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * rendering a quad into just those buffers. Thus, we have to * make sure the 3D engine is configured correctly. */ - else if ((dev_priv->microcode_version == UCODE_R200) && - (flags & (RADEON_DEPTH | RADEON_STENCIL))) { + else if ((dev_priv->chip_family >= CHIP_R200) && + (dev_priv->chip_family <= CHIP_RV280) && + (flags & (RADEON_DEPTH | RADEON_STENCIL))) { int tempPP_CNTL; int tempRE_CNTL; @@ -2889,7 +2895,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file orig_nbox = cmdbuf->nbox; - if (dev_priv->microcode_version == UCODE_R300) { + if (dev_priv->chip_family >= CHIP_R300) { int temp; temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); -- cgit v1.2.3 From 6ac1f8a760e1e757569a5f6f420df91cf203b02d Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 19 Jul 2008 13:15:23 -0400 Subject: Update vblank code to new API In my last push I forgot to convert users of drm_update_vblank_count over to drm_vblank_get/put, since that's where any interrupt off->on update accounting is done now. Since the modeset ioctl did something similar (an open coded update of the counter) convert it over to using get/put too, which saves us from having to deal with every combination of interrupt off & on between calls. --- linux-core/drm_irq.c | 72 +++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 75e53da9..1f887d31 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -412,7 +412,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) unsigned long irqflags; int ret = 0; - spin_lock_irqsave(&dev->vbl_lock, irqflags); + spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && !dev->vblank_enabled[crtc]) { @@ -455,47 +455,49 @@ EXPORT_SYMBOL(drm_vblank_put); * * Generally the counter will reset across mode sets. If interrupts are * enabled around this call, we don't have to do anything since the counter - * will have already been incremented. If interrupts are off though, we need - * to make sure we account for the lost events at %_DRM_POST_MODESET time. + * will have already been incremented. */ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; unsigned long irqflags; - u32 new, diff; int crtc, ret = 0; + /* If drm_vblank_init() hasn't been called yet, just no-op */ + if (!dev->num_crtcs) + goto out; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = -EINVAL; goto out; } + /* + * To avoid all the problems that might happen if interrupts + * were enabled/disabled around or between these calls, we just + * have the kernel take a reference on the CRTC (just once though + * to avoid corrupting the count if multiple, mismatch calls occur), + * so that interrupts remain enabled in the interim. + */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - if (!dev->vblank_enabled[crtc]) { - dev->vblank_premodeset[crtc] = - dev->driver->get_vblank_counter(dev, crtc); + if (!dev->vblank_suspend[crtc]) { + spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_suspend[crtc] = 1; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + drm_vblank_get(dev, crtc); } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - new = dev->driver->get_vblank_counter(dev, crtc); - if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { - if (new > dev->vblank_premodeset[crtc]) - diff = dev->vblank_premodeset[crtc] - new; - else - diff = new; - atomic_add(diff, &dev->_vblank_count[crtc]); + if (dev->vblank_suspend[crtc]) { + spin_lock_irqsave(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + dev->vblank_suspend[crtc] = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + drm_vblank_put(dev, crtc); } - dev->vblank_suspend[crtc] = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); break; default: ret = -EINVAL; @@ -549,6 +551,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (crtc >= dev->num_crtcs) return -EINVAL; + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -558,7 +563,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, case _DRM_VBLANK_ABSOLUTE: break; default: - return -EINVAL; + ret = -EINVAL; + goto done; } if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -571,8 +577,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; struct drm_vbl_sig *vbl_sig; - if (dev->vblank_suspend[crtc]) - return -EBUSY; + if (dev->vblank_suspend[crtc]) { + ret = -EBUSY; + goto done; + } spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -594,15 +602,18 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (atomic_read(&dev->vbl_signal_pending) >= 100) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - return -EBUSY; + ret = -EBUSY; + goto done; } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); vbl_sig = drm_calloc(1, sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER); - if (!vbl_sig) - return -ENOMEM; + if (!vbl_sig) { + ret = -ENOMEM; + goto done; + } ret = drm_vblank_get(dev, crtc); if (ret) { @@ -626,13 +637,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->reply.sequence = seq; } else { if (!dev->vblank_suspend[crtc]) { - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, ((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); } if (ret != -EINTR) { @@ -646,7 +653,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, } } - done: +done: + drm_vblank_put(dev, crtc); return ret; } -- cgit v1.2.3 From 04893aa99abfbed8eb6d7067a974fa1f31193c87 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Sat, 19 Jul 2008 13:18:02 -0400 Subject: i915: convert to using drm_vblank_get/put around vblank counter usage All interrupt off vblank count updates are done in drm_vblank_get/put now, so convert users of the vblank counter over to that interface. --- shared-core/i915_irq.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ecb2d7fc..b95d0f1e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -769,6 +769,13 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + /* + * We take the ref here and put it when the swap actually completes + * in the tasklet. + */ + ret = drm_vblank_get(dev, pipe); + if (ret) + return ret; curseq = drm_vblank_count(dev, pipe); if (seqtype == _DRM_VBLANK_RELATIVE) @@ -779,6 +786,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, swap->sequence = curseq + 1; } else { DRM_DEBUG("Missed target sequence\n"); + drm_vblank_put(dev, pipe); return -EINVAL; } } @@ -800,6 +808,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, irqflags); DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable); + drm_vblank_put(dev, pipe); return -EINVAL; } @@ -807,6 +816,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + drm_vblank_put(dev, pipe); return 0; } } @@ -830,6 +840,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, if (dev_priv->swaps_pending >= 100) { DRM_DEBUG("Too many swaps queued\n"); + drm_vblank_put(dev, pipe); return -EBUSY; } @@ -837,17 +848,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data, if (!vbl_swap) { DRM_ERROR("Failed to allocate memory to queue swap\n"); + drm_vblank_put(dev, pipe); return -ENOMEM; } DRM_DEBUG("\n"); - ret = drm_vblank_get(dev, pipe); - if (ret) { - drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); - return ret; - } - vbl_swap->drw_id = swap->drawable; vbl_swap->plane = plane; vbl_swap->sequence = swap->sequence; -- cgit v1.2.3 From 014935b680d12856a01c0b2fe6077a38d69d14d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 08:13:45 +0200 Subject: Remove obsolete dev->vblank_suspend[crtc] tests. Caused drm_update_vblank_count() not to do its thing when called from drm_modeset_ctl() -> drm_vblank_get(). The vblank functionality no longer needs to be suspended during a modeset, so rename the field to vblank_inmodeset. --- linux-core/drmP.h | 2 +- linux-core/drm_irq.c | 30 ++++++++++-------------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 45a599b4..37dd60f9 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -851,7 +851,7 @@ struct drm_device { int *vblank_enabled; /* so we don't call enable more than once per disable */ u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ - int *vblank_suspend; /* Don't wait while crtc is likely disabled */ + int *vblank_inmodeset; /* Display driver is setting mode */ struct timer_list vblank_disable_timer; u32 max_vblank_count; /**< size of vblank counter register */ diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 1f887d31..ec1e5be6 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -118,7 +118,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) DRM_MEM_DRIVER); drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; @@ -168,9 +168,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_premodeset) goto err; - dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), + dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), DRM_MEM_DRIVER); - if (!dev->vblank_suspend) + if (!dev->vblank_inmodeset) goto err; /* Zero per-crtc vblank stuff */ @@ -363,9 +363,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -483,18 +480,18 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - if (!dev->vblank_suspend[crtc]) { + if (!dev->vblank_inmodeset[crtc]) { spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_suspend[crtc] = 1; + dev->vblank_inmodeset[crtc] = 1; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); drm_vblank_get(dev, crtc); } break; case _DRM_POST_MODESET: - if (dev->vblank_suspend[crtc]) { + if (dev->vblank_inmodeset[crtc]) { spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_disable_allowed = 1; - dev->vblank_suspend[crtc] = 0; + dev->vblank_inmodeset[crtc] = 0; spin_unlock_irqrestore(&dev->vbl_lock, irqflags); drm_vblank_put(dev, crtc); } @@ -577,11 +574,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct list_head *vbl_sigs = &dev->vbl_sigs[crtc]; struct drm_vbl_sig *vbl_sig; - if (dev->vblank_suspend[crtc]) { - ret = -EBUSY; - goto done; - } - spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -636,11 +628,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->reply.sequence = seq; } else { - if (!dev->vblank_suspend[crtc]) { - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - ((drm_vblank_count(dev, crtc) - - vblwait->request.sequence) <= (1 << 23))); - } + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23))); if (ret != -EINTR) { struct timeval now; -- cgit v1.2.3 From 205aff6a5cc7b037f53b6bbcd3fa5b2d42f43f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 08:16:55 +0200 Subject: vblank-rework rework cleanups. Remove some dead/obsolete code and make drm_update_vblank_count() static. --- linux-core/drmP.h | 4 ---- linux-core/drm_irq.c | 30 ++++-------------------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 37dd60f9..6e4d6dda 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -848,9 +848,6 @@ struct drm_device { atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ - int *vblank_enabled; /* so we don't call enable more than - once per disable */ - u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ int *vblank_inmodeset; /* Display driver is setting mode */ struct timer_list vblank_disable_timer; @@ -1153,7 +1150,6 @@ extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file * extern int drm_vblank_wait(struct drm_device * dev, unsigned int *vbl_seq); extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*)); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); -extern void drm_update_vblank_count(struct drm_device *dev, int crtc); extern void drm_handle_vblank(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index ec1e5be6..26aecdf9 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -82,13 +82,11 @@ static void vblank_disable_fn(unsigned long arg) for (i = 0; i < dev->num_crtcs; i++) { spin_lock_irqsave(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank_refcount[i]) == 0 && - dev->vblank_enabled[i]) { + if (atomic_read(&dev->vblank_refcount[i]) == 0) { DRM_DEBUG("disabling vblank on crtc %d\n", i); dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i); dev->driver->disable_vblank(dev, i); - dev->vblank_enabled[i] = 0; } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } @@ -112,12 +110,8 @@ static void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * dev->num_crtcs, DRM_MEM_DRIVER); @@ -154,20 +148,10 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_enabled) - goto err; - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), DRM_MEM_DRIVER); if (!dev->vblank_inmodeset) @@ -359,7 +343,7 @@ EXPORT_SYMBOL(drm_vblank_count); * Note: caller must hold dev->vbl_lock since this reads & writes * device vblank fields. */ -void drm_update_vblank_count(struct drm_device *dev, int crtc) +static void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; @@ -385,7 +369,6 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) } else { diff = cur_vblank - dev->last_vblank[crtc]; } - dev->last_vblank[crtc] = cur_vblank; DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); @@ -411,15 +394,12 @@ int drm_vblank_get(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && - !dev->vblank_enabled[crtc]) { + if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { ret = dev->driver->enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else { - dev->vblank_enabled[crtc] = 1; + else drm_update_vblank_count(dev, crtc); - } } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -481,9 +461,7 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: if (!dev->vblank_inmodeset[crtc]) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_inmodeset[crtc] = 1; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); drm_vblank_get(dev, crtc); } break; -- cgit v1.2.3 From e4feaf506db0bc8ad15dbb5154e093478c3dd56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 08:16:59 +0200 Subject: radeon: Post-vblank-rework-rework cleanups. Thanks to the reworked vblank-rework, we can just use the hardware frame counter directly, and make the RADEON_PARAM_VBLANK_CRTC getparam just return what was set by the corresponding setparam. --- shared-core/radeon_irq.c | 57 +++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index f58d7fa2..a766f0ed 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -254,35 +254,27 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr) u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) { drm_radeon_private_t *dev_priv = dev->dev_private; - u32 crtc_cnt_reg, crtc_status_reg; - if (!dev_priv) { + if (!dev_priv || crtc < 0 || crtc > 1) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } + if (crtc < 0 || crtc > 1) { + DRM_ERROR("Invalid crtc %d\n", crtc); + return -EINVAL; + } + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { - if (crtc == 0) { - crtc_cnt_reg = R500_D1CRTC_FRAME_COUNT; - crtc_status_reg = R500_D1CRTC_STATUS; - } else if (crtc == 1) { - crtc_cnt_reg = R500_D2CRTC_FRAME_COUNT; - crtc_status_reg = R500_D2CRTC_STATUS; - } else - return -EINVAL; - return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1); - + if (crtc == 0) + return RADEON_READ(R500_D1CRTC_FRAME_COUNT); + else + return RADEON_READ(R500_D2CRTC_FRAME_COUNT); } else { - if (crtc == 0) { - crtc_cnt_reg = RADEON_CRTC_CRNT_FRAME; - crtc_status_reg = RADEON_CRTC_STATUS; - } else if (crtc == 1) { - crtc_cnt_reg = RADEON_CRTC2_CRNT_FRAME; - crtc_status_reg = RADEON_CRTC2_STATUS; - } else { - return -EINVAL; - } - return RADEON_READ(crtc_cnt_reg) + (RADEON_READ(crtc_status_reg) & 1); + if (crtc == 0) + return RADEON_READ(RADEON_CRTC_CRNT_FRAME); + else + return RADEON_READ(RADEON_CRTC2_CRNT_FRAME); } } @@ -382,27 +374,8 @@ void radeon_driver_irq_uninstall(struct drm_device * dev) int radeon_vblank_crtc_get(struct drm_device *dev) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private; - u32 flag; - u32 value; - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) { - flag = RADEON_READ(R500_DxMODE_INT_MASK); - value = 0; - if (flag & R500_D1MODE_INT_MASK) - value |= DRM_RADEON_VBLANK_CRTC1; - - if (flag & R500_D2MODE_INT_MASK) - value |= DRM_RADEON_VBLANK_CRTC2; - } else { - flag = RADEON_READ(RADEON_GEN_INT_CNTL); - value = 0; - if (flag & RADEON_CRTC_VBLANK_MASK) - value |= DRM_RADEON_VBLANK_CRTC1; - - if (flag & RADEON_CRTC2_VBLANK_MASK) - value |= DRM_RADEON_VBLANK_CRTC2; - } - return value; + return dev_priv->vblank_crtc; } int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value) -- cgit v1.2.3 From f529a510d200c87919084fda1e053545c25ebeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 08:16:59 +0200 Subject: Drop workaround for driver vblank counter going backwards. The driver code that caused this is no longer necessary and has been dropped. --- linux-core/drm_irq.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 26aecdf9..7c056114 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -355,19 +355,12 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver->get_vblank_counter(dev, crtc); + diff = cur_vblank - dev->last_vblank[crtc]; if (cur_vblank < dev->last_vblank[crtc]) { - if (cur_vblank == dev->last_vblank[crtc] - 1) { - diff = 0; - } else { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } + diff += dev->max_vblank_count; DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", crtc, dev->last_vblank[crtc], cur_vblank, diff); - } else { - diff = cur_vblank - dev->last_vblank[crtc]; } DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", -- cgit v1.2.3 From 4be367b84b5a6691c28d9419039ea8113ebabc92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 11:48:04 +0200 Subject: Reinstate dev->vblank_enabled[]. I incorrectly thought it was obsolete. --- linux-core/drmP.h | 2 ++ linux-core/drm_irq.c | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6e4d6dda..19168cd7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -848,6 +848,8 @@ struct drm_device { atomic_t *vblank_refcount; /* number of users of vblank interrupts per crtc */ u32 *last_vblank; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ + int *vblank_enabled; /* so we don't call enable more than + once per disable */ int *vblank_inmodeset; /* Display driver is setting mode */ struct timer_list vblank_disable_timer; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 7c056114..d0d6f987 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -82,11 +82,13 @@ static void vblank_disable_fn(unsigned long arg) for (i = 0; i < dev->num_crtcs; i++) { spin_lock_irqsave(&dev->vbl_lock, irqflags); - if (atomic_read(&dev->vblank_refcount[i]) == 0) { + if (atomic_read(&dev->vblank_refcount[i]) == 0 && + dev->vblank_enabled[i]) { DRM_DEBUG("disabling vblank on crtc %d\n", i); dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i); dev->driver->disable_vblank(dev, i); + dev->vblank_enabled[i] = 0; } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } @@ -110,6 +112,8 @@ static void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * dev->num_crtcs, DRM_MEM_DRIVER); + drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * + dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * @@ -148,6 +152,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->vblank_refcount) goto err; + dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), + DRM_MEM_DRIVER); + if (!dev->vblank_enabled) + goto err; + dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); if (!dev->last_vblank) goto err; @@ -387,12 +396,15 @@ int drm_vblank_get(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { + if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1 && + !dev->vblank_enabled[crtc]) { ret = dev->driver->enable_vblank(dev, crtc); if (ret) atomic_dec(&dev->vblank_refcount[crtc]); - else + else { + dev->vblank_enabled[crtc] = 1; drm_update_vblank_count(dev, crtc); + } } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); -- cgit v1.2.3 From b5cddbcc1536d70dfa9fec833732b2a715d82e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 21 Jul 2008 13:43:12 +0200 Subject: Remove accidental leftover tests. Thanks to Nicolai Haehnle for pointing this out on IRC. --- shared-core/radeon_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index a766f0ed..69569961 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -255,7 +255,7 @@ u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc) { drm_radeon_private_t *dev_priv = dev->dev_private; - if (!dev_priv || crtc < 0 || crtc > 1) { + if (!dev_priv) { DRM_ERROR("called with no initialization\n"); return -EINVAL; } -- cgit v1.2.3 From f57f01f02843747d423f2e1c2936f0b987c5b067 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Mon, 21 Jul 2008 18:04:02 -0400 Subject: [FreeBSD] Improve upper_32_bits define. Thanks to airlied. --- bsd-core/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 2f2ffb3c..6b91a76b 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -632,7 +632,7 @@ struct drm_ati_pcigart_info { #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1) #endif -#define upper_32_bits(_val) (((u64)(_val)) >> 32) +#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) struct drm_driver_info { int (*load)(struct drm_device *, unsigned long flags); -- cgit v1.2.3 From c669489813c089b5aa176367e696396b071a4bee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 22 Jul 2008 18:10:03 +1000 Subject: radeon: fix type DST vs Z cache flush --- shared-core/radeon_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 9bd23be1..8c9ebd86 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1312,7 +1312,7 @@ do { \ OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \ OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE); \ } else { \ - OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0)); \ + OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); \ OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); \ } \ } while (0) -- cgit v1.2.3 From 589f9681734770dce966bcded7d3d4bd78f4bea5 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 22 Jul 2008 18:47:27 +1000 Subject: radeon: fix typo with a better typo --- shared-core/radeon_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 8c9ebd86..65569db9 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1312,7 +1312,7 @@ do { \ OUT_RING(CP_PACKET0(RADEON_RB3D_ZCACHE_CTLSTAT, 0)); \ OUT_RING(RADEON_RB3D_ZC_FLUSH | RADEON_RB3D_ZC_FREE); \ } else { \ - OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0)); \ + OUT_RING(CP_PACKET0(R300_ZB_ZCACHE_CTLSTAT, 0)); \ OUT_RING(R300_ZC_FLUSH | R300_ZC_FREE); \ } \ } while (0) -- cgit v1.2.3 From 965a72202b439068e62ac341990f51953457b202 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Wed, 23 Jul 2008 19:55:06 -0400 Subject: i915: Move all of the irq install/uninstall to load time. This resolves a panic on FreeBSD which was caused by trying to re-initialize the swap lock. It's just much easier to initialize all of the locks at load time. It should also ensure that the vblank structures are available earlier. --- shared-core/i915_dma.c | 47 ++++++++++++++++++++++++++++++++++++++++++- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 54 +++----------------------------------------------- 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ad6e1293..e57580fe 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -1010,7 +1010,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv; unsigned long base, size; - int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; + int ret = 0, num_pipes = 2, mmio_bar = IS_I9XX(dev) ? 0 : 1; /* i915 has 4 more counters */ dev->counters += 4; @@ -1041,12 +1041,57 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_opregion_init(dev); #endif + I915_WRITE16(HWSTAM, 0xeffe); + I915_WRITE16(IMR, 0x0); + I915_WRITE16(IER, 0x0); + + DRM_SPININIT(&dev_priv->swaps_lock, "swap"); + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + + DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); + dev_priv->user_irq_refcount = 0; + dev_priv->irq_enable_reg = 0; + + ret = drm_vblank_init(dev, num_pipes); + if (ret) + return ret; + + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; + dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ + + i915_enable_interrupt(dev); + DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); + return ret; } int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + u32 temp; + + if (dev_priv) { + dev_priv->vblank_pipe = 0; + + dev_priv->irq_enabled = 0; + I915_WRITE(HWSTAM, 0xffffffff); + I915_WRITE(IMR, 0xffffffff); + I915_WRITE(IER, 0x0); + + temp = I915_READ(PIPEASTAT); + I915_WRITE(PIPEASTAT, temp); + temp = I915_READ(PIPEBSTAT); + I915_WRITE(PIPEBSTAT, temp); + temp = I915_READ(IIR); + I915_WRITE(IIR, temp); + } if (dev_priv->mmio_map) drm_rmmap(dev, dev_priv->mmio_map); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 421572cd..a77fcf04 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -307,6 +307,7 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); extern int i915_driver_irq_postinstall(struct drm_device * dev); extern void i915_driver_irq_uninstall(struct drm_device * dev); +extern void i915_enable_interrupt(struct drm_device *dev); extern int i915_vblank_pipe_set(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_vblank_pipe_get(struct drm_device *dev, void *data, diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index b95d0f1e..135d6159 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -668,7 +668,7 @@ void i915_disable_vblank(struct drm_device *dev, int plane) } } -static void i915_enable_interrupt (struct drm_device *dev) +void i915_enable_interrupt (struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -876,63 +876,15 @@ int i915_vblank_swap(struct drm_device *dev, void *data, */ void i915_driver_irq_preinstall(struct drm_device * dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - - I915_WRITE16(HWSTAM, 0xeffe); - I915_WRITE16(IMR, 0x0); - I915_WRITE16(IER, 0x0); + return; } int i915_driver_irq_postinstall(struct drm_device * dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - int ret, num_pipes = 2; - - DRM_SPININIT(&dev_priv->swaps_lock, "swap"); - INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); - dev_priv->swaps_pending = 0; - - DRM_SPININIT(&dev_priv->user_irq_lock, "userirq"); - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = 0; - - ret = drm_vblank_init(dev, num_pipes); - if (ret) - return ret; - - dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - - i915_enable_interrupt(dev); - DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); - - /* - * Initialize the hardware status page IRQ location. - */ - - I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); return 0; } void i915_driver_irq_uninstall(struct drm_device * dev) { - drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 temp; - - if (!dev_priv) - return; - - dev_priv->vblank_pipe = 0; - - dev_priv->irq_enabled = 0; - I915_WRITE(HWSTAM, 0xffffffff); - I915_WRITE(IMR, 0xffffffff); - I915_WRITE(IER, 0x0); - - temp = I915_READ(PIPEASTAT); - I915_WRITE(PIPEASTAT, temp); - temp = I915_READ(PIPEBSTAT); - I915_WRITE(PIPEBSTAT, temp); - temp = I915_READ(IIR); - I915_WRITE(IIR, temp); + return; } -- cgit v1.2.3 From 2580a065d81be645a14af1e91b8441f7e72fcbe4 Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Thu, 24 Jul 2008 00:21:00 -0400 Subject: [FreeBSD] Catch up to linux on vblank-rework --- bsd-core/drmP.h | 4 +-- bsd-core/drm_irq.c | 102 +++++++++++++++++++++-------------------------------- 2 files changed, 42 insertions(+), 64 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 6b91a76b..326b2202 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -798,8 +798,7 @@ struct drm_device { /* for wraparound handling */ int *vblank_enabled; /* so we don't call enable more than */ /* once per disable */ - u32 *vblank_premodeset; /* for compensation of spurious wraparounds */ - int *vblank_suspend; /* Don't wait while crtc is likely disabled */ + int *vblank_inmodeset; /* Display driver is setting mode */ struct callout vblank_disable_timer; u32 max_vblank_count; /* size of vblank counter register */ int num_crtcs; @@ -932,7 +931,6 @@ void drm_handle_vblank(struct drm_device *dev, int crtc); u32 drm_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_get(struct drm_device *dev, int crtc); void drm_vblank_put(struct drm_device *dev, int crtc); -void drm_update_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); int drm_vblank_init(struct drm_device *dev, int num_crtcs); void drm_vbl_send_signals(struct drm_device *dev, int crtc); diff --git a/bsd-core/drm_irq.c b/bsd-core/drm_irq.c index 4b515ad8..6e21d41c 100644 --- a/bsd-core/drm_irq.c +++ b/bsd-core/drm_irq.c @@ -124,9 +124,7 @@ static void drm_vblank_cleanup(struct drm_device *dev) dev->num_crtcs, DRM_MEM_DRIVER); drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_suspend, sizeof(*dev->vblank_suspend) * + drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * dev->num_crtcs, DRM_MEM_DRIVER); dev->num_crtcs = 0; @@ -169,14 +167,9 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) if (!dev->last_vblank) goto err; - dev->vblank_premodeset = drm_calloc(num_crtcs, sizeof(u32), + dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), DRM_MEM_DRIVER); - if (!dev->vblank_premodeset) - goto err; - - dev->vblank_suspend = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); - if (!dev->vblank_suspend) + if (!dev->vblank_inmodeset) goto err; /* Zero per-crtc vblank stuff */ @@ -340,13 +333,10 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) return atomic_read(&dev->_vblank_count[crtc]); } -void drm_update_vblank_count(struct drm_device *dev, int crtc) +static void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -355,21 +345,13 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) * a long time. */ cur_vblank = dev->driver.get_vblank_counter(dev, crtc); + diff = cur_vblank - dev->last_vblank[crtc]; if (cur_vblank < dev->last_vblank[crtc]) { - if (cur_vblank == dev->last_vblank[crtc] - 1) { - diff = 0; - } else { - diff = dev->max_vblank_count - - dev->last_vblank[crtc]; - diff += cur_vblank; - } + diff += dev->max_vblank_count; DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", crtc, dev->last_vblank[crtc], cur_vblank, diff); - } else { - diff = cur_vblank - dev->last_vblank[crtc]; } - dev->last_vblank[crtc] = cur_vblank; DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); @@ -408,7 +390,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc) /* Last user schedules interrupt disable */ atomic_subtract_acq_int(&dev->vblank_refcount[crtc], 1); if (dev->vblank_refcount[crtc] == 0) - callout_reset(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ, + callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); } @@ -418,39 +400,40 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, { struct drm_modeset_ctl *modeset = data; unsigned long irqflags; - u32 new, diff; int crtc, ret = 0; + /* If drm_vblank_init() hasn't been called yet, just no-op */ + if (!dev->num_crtcs) + goto out; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = EINVAL; goto out; } + /* + * To avoid all the problems that might happen if interrupts + * were enabled/disabled around or between these calls, we just + * have the kernel take a reference on the CRTC (just once though + * to avoid corrupting the count if multiple, mismatch calls occur), + * so that interrupts remain enabled in the interim. + */ switch (modeset->cmd) { case _DRM_PRE_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - if (!dev->vblank_enabled[crtc]) { - dev->vblank_premodeset[crtc] = - dev->driver.get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; + if (!dev->vblank_inmodeset[crtc]) { + dev->vblank_inmodeset[crtc] = 1; + drm_vblank_get(dev, crtc); } - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; case _DRM_POST_MODESET: - DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - new = dev->driver.get_vblank_counter(dev, crtc); - if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { - if (new > dev->vblank_premodeset[crtc]) - diff = dev->vblank_premodeset[crtc] - new; - else - diff = new; - atomic_add(diff, &dev->_vblank_count[crtc]); + if (dev->vblank_inmodeset[crtc]) { + DRM_SPINLOCK_IRQSAVE(&dev->vbl_lock, irqflags); + dev->vblank_disable_allowed = 1; + dev->vblank_inmodeset[crtc] = 0; + DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); + drm_vblank_put(dev, crtc); } - dev->vblank_suspend[crtc] = 0; - DRM_SPINUNLOCK_IRQRESTORE(&dev->vbl_lock, irqflags); break; default: ret = EINVAL; @@ -484,6 +467,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (crtc >= dev->num_crtcs) return EINVAL; + ret = drm_vblank_get(dev, crtc); + if (ret) + return ret; seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { @@ -493,7 +479,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr case _DRM_VBLANK_ABSOLUTE: break; default: - return EINVAL; + ret = EINVAL; + goto done; } if ((flags & _DRM_VBLANK_NEXTONMISS) && @@ -508,9 +495,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr if (vbl_sig == NULL) return ENOMEM; - if (dev->vblank_suspend[crtc]) - return EBUSY; - vbl_sig->sequence = vblwait->request.sequence; vbl_sig->signo = vblwait->request.signal; vbl_sig->pid = DRM_CURRENTPID; @@ -524,19 +508,13 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr #endif ret = EINVAL; } else { - if (!dev->vblank_suspend[crtc]) { - DRM_LOCK(); - /* shared code returns -errno */ - - ret = drm_vblank_get(dev, crtc); - if (ret) - return ret; - DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, - ((drm_vblank_count(dev, crtc) - - vblwait->request.sequence) <= (1 << 23))); - drm_vblank_put(dev, crtc); - DRM_UNLOCK(); - } + DRM_LOCK(); + /* shared code returns -errno */ + + DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, + ((drm_vblank_count(dev, crtc) + - vblwait->request.sequence) <= (1 << 23))); + DRM_UNLOCK(); if (ret != EINTR) { struct timeval now; @@ -548,6 +526,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr } } +done: + drm_vblank_put(dev, crtc); return ret; } -- cgit v1.2.3 From 50db5aefa18283282400fd4a5090b686b5870206 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 25 Jul 2008 13:30:08 +1000 Subject: drm: don't set the signal blocker on the master process. this lets us debug the X server through xkb startup. Not sure what the correct answer is, probably X needs to drop the lock when execing stuff, with input hotplug it can get xkb stuff at any time I believe. --- linux-core/drm_lock.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index d4c2da0c..573213de 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -105,14 +105,19 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ret ? "interrupted" : "has lock"); if (ret) return ret; - sigemptyset(&dev->sigmask); - sigaddset(&dev->sigmask, SIGSTOP); - sigaddset(&dev->sigmask, SIGTSTP); - sigaddset(&dev->sigmask, SIGTTIN); - sigaddset(&dev->sigmask, SIGTTOU); - dev->sigdata.context = lock->context; - dev->sigdata.lock = dev->lock.hw_lock; - block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + /* don't set the block all signals on the master process for now + * really probably not the correct answer but lets us debug xkb + * xserver for now */ + if (!file_priv->master) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock->context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + } if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) dev->driver->dma_ready(dev); -- cgit v1.2.3 From 7a3d6624c47d87bdd46f5394b8cc5130c7a4ed0d Mon Sep 17 00:00:00 2001 From: Robert Noland Date: Fri, 25 Jul 2008 13:46:28 -0400 Subject: [FreeBSD] Duh, we need to actually define the drm_modeset_ctl... --- bsd-core/drm_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 9bd6079f..771e5554 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -125,6 +125,7 @@ static drm_ioctl_desc_t drm_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; -- cgit v1.2.3 From c3d463840c902a28221f1514bfb69fb7905a05c2 Mon Sep 17 00:00:00 2001 From: Nicolai Haehnle Date: Sat, 26 Jul 2008 11:39:10 +0200 Subject: r300_cmdbuf: Always emit INDX_BUFFER immediately after DRAW_INDEX DRAW_INDEX writes a vertex count to VAP_VF_CNTL. Docs say that behaviour is undefined (i.e. lockups happen) when this write is not followed by the right number of vertex indices. Thus we used to do the wrong thing when drawing across many cliprects was necessary, because we emitted a sequence DRAW_INDEX, DRAW_INDEX, INDX_BUFFER, INDX_BUFFER instead of DRAW_INDEX, INDX_BUFFER, DRAW_INDEX, INDX_BUFFER The latter is what we're doing now and which ought to be correct. --- shared-core/r300_cmdbuf.c | 80 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index 254c0691..ed787461 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -578,22 +578,23 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, return 0; } -static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, - drm_radeon_kcmd_buffer_t *cmdbuf) +static __inline__ int r300_emit_draw_indx_2(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) { - u32 *cmd = (u32 *) cmdbuf->buf; - int count, ret; + u32 *cmd; + int count; + int expected_count; RING_LOCALS; - count=(cmd[0]>>16) & 0x3fff; + cmd = (u32 *) cmdbuf->buf; + count = (cmd[0]>>16) & 0x3fff; + expected_count = cmd[1] >> 16; + if (!(cmd[1] & R300_VAP_VF_CNTL__INDEX_SIZE_32bit)) + expected_count = (expected_count+1)/2; - if ((cmd[1] & 0x8000ffff) != 0x80000810) { - DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); - return -EINVAL; - } - ret = !radeon_check_offset(dev_priv, cmd[2]); - if (ret) { - DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + if (count && count != expected_count) { + DRM_ERROR("3D_DRAW_INDX_2: packet size %i, expected %i\n", + count, expected_count); return -EINVAL; } @@ -605,6 +606,50 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, cmdbuf->buf += (count+2)*4; cmdbuf->bufsz -= (count+2)*4; + if (!count) { + drm_r300_cmd_header_t header; + + if (cmdbuf->bufsz < 4*4 + sizeof(header)) { + DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER, but stream is too short.\n"); + return -EINVAL; + } + + header.u = *(unsigned int *)cmdbuf->buf; + + cmdbuf->buf += sizeof(header); + cmdbuf->bufsz -= sizeof(header); + cmd = (u32 *) cmdbuf->buf; + + if (header.header.cmd_type != R300_CMD_PACKET3 || + header.packet3.packet != R300_CMD_PACKET3_RAW || + cmd[0] != CP_PACKET3(RADEON_CP_INDX_BUFFER, 2)) { + DRM_ERROR("3D_DRAW_INDX_2: expect subsequent INDX_BUFFER.\n"); + return -EINVAL; + } + + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return -EINVAL; + } + if (!radeon_check_offset(dev_priv, cmd[2])) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return -EINVAL; + } + if (cmd[3] != expected_count) { + DRM_ERROR("INDX_BUFFER: buffer size %i, expected %i\n", + cmd[3], expected_count); + return -EINVAL; + } + + BEGIN_RING(4); + OUT_RING(cmd[0]); + OUT_RING_TABLE((int *)(cmdbuf->buf + 4), 3); + ADVANCE_RING(); + + cmdbuf->buf += 4*4; + cmdbuf->bufsz -= 4*4; + } + return 0; } @@ -649,18 +694,21 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, return r300_emit_bitblt_multi(dev_priv, cmdbuf); case RADEON_CP_INDX_BUFFER: - /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ - return r300_emit_indx_buffer(dev_priv, cmdbuf); + DRM_ERROR("packet3 INDX_BUFFER without preceding 3D_DRAW_INDX_2 is illegal.\n"); + return -EINVAL; case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ + dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | + RADEON_PURGE_EMITED); + break; case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ /* whenever we send vertex we clear flush & purge */ dev_priv->track_flush &= ~(RADEON_FLUSH_EMITED | RADEON_PURGE_EMITED); - break; + return r300_emit_draw_indx_2(dev_priv, cmdbuf); case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: /* these packets are safe */ @@ -758,7 +806,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) { uint32_t cache_z, cache_3d, cache_2d; RING_LOCALS; - + cache_z = R300_ZC_FLUSH; cache_2d = R300_RB2D_DC_FLUSH; cache_3d = R300_RB3D_DC_FLUSH; -- cgit v1.2.3 From 514c05cebe31a62f827a76f348d35596bef97811 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Sat, 26 Jul 2008 16:49:14 +0200 Subject: radeon: Add suspend/resume hooks for saving/clearing/restoring interrupts. Fixes http://bugs.freedesktop.org/show_bug.cgi?id=16799 . --- linux-core/radeon_drv.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index f0f3320e..934fa0b9 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -52,6 +52,28 @@ static int dri_library_name(struct drm_device * dev, char * buf) "r300")); } +static int radeon_suspend(struct drm_device *dev, pm_message_t state) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + /* Disable *all* interrupts */ + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, 0); + RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); + return 0; +} + +static int radeon_resume(struct drm_device *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + /* Restore interrupt registers */ + if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS690) + RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); + RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); + return 0; +} + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; @@ -69,6 +91,8 @@ static struct drm_driver driver = { .postclose = radeon_driver_postclose, .lastclose = radeon_driver_lastclose, .unload = radeon_driver_unload, + .suspend = radeon_suspend, + .resume = radeon_resume, .get_vblank_counter = radeon_get_vblank_counter, .enable_vblank = radeon_enable_vblank, .disable_vblank = radeon_disable_vblank, -- cgit v1.2.3