diff options
-rw-r--r-- | linux-core/mga_drv.c | 7 | ||||
-rw-r--r-- | shared-core/mga_drv.h | 11 | ||||
-rw-r--r-- | shared-core/mga_irq.c | 79 |
3 files changed, 67 insertions, 30 deletions
diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index ef6f1e44..6419cbdc 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -46,15 +46,16 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | - DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | - DRIVER_IRQ_VBL, + DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED, .dev_priv_size = sizeof (drm_mga_buf_priv_t), .load = mga_driver_load, .unload = mga_driver_unload, .lastclose = mga_driver_lastclose, .dma_quiescent = mga_driver_dma_quiescent, .device_is_agp = mga_driver_device_is_agp, - .vblank_wait = mga_driver_vblank_wait, + .get_vblank_counter = mga_get_vblank_counter, + .enable_vblank = mga_enable_vblank, + .disable_vblank = mga_disable_vblank, .irq_preinstall = mga_driver_irq_preinstall, .irq_postinstall = mga_driver_irq_postinstall, .irq_uninstall = mga_driver_irq_uninstall, diff --git a/shared-core/mga_drv.h b/shared-core/mga_drv.h index bce82135..4764edab 100644 --- a/shared-core/mga_drv.h +++ b/shared-core/mga_drv.h @@ -113,13 +113,14 @@ typedef struct drm_mga_private { * \sa drm_mga_private_t::mmio */ /*@{*/ - u32 mmio_base; /**< Bus address of base of MMIO. */ - u32 mmio_size; /**< Size of the MMIO region. */ + u32 mmio_base; /**< Bus address of base of MMIO. */ + u32 mmio_size; /**< Size of the MMIO region. */ /*@}*/ u32 clear_cmd; u32 maccess; + atomic_t vbl_received; /**< Number of vblanks received. */ wait_queue_head_t fence_queue; atomic_t last_fence_retired; u32 next_fence_to_post; @@ -177,10 +178,12 @@ extern int mga_warp_init(drm_mga_private_t * dev_priv); /* mga_irq.c */ extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence); -extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence); +extern int mga_enable_vblank(drm_device_t *dev, int crtc); +extern void mga_disable_vblank(drm_device_t *dev, int crtc); +extern u32 mga_get_vblank_counter(drm_device_t *dev, int crtc); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); extern void mga_driver_irq_preinstall(drm_device_t * dev); -extern void mga_driver_irq_postinstall(drm_device_t * dev); +extern int mga_driver_irq_postinstall(drm_device_t * dev); extern void mga_driver_irq_uninstall(drm_device_t * dev); extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); diff --git a/shared-core/mga_irq.c b/shared-core/mga_irq.c index 490d1fbb..a49a9b6e 100644 --- a/shared-core/mga_irq.c +++ b/shared-core/mga_irq.c @@ -36,6 +36,20 @@ #include "mga_drm.h" #include "mga_drv.h" +u32 mga_get_vblank_counter(drm_device_t *dev, int crtc) +{ + const drm_mga_private_t *const dev_priv = + (drm_mga_private_t *) dev->dev_private; + + if (crtc != 0) { + return 0; + } + + + return atomic_read(&dev_priv->vbl_received); +} + + irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -48,9 +62,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) /* VBLANK interrupt */ if (status & MGA_VLINEPEN) { MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); - atomic_inc(&dev->vbl_received); - DRM_WAKEUP(&dev->vbl_queue); - drm_vbl_send_signals(dev); + atomic_inc(&dev_priv->vbl_received); + drm_handle_vblank(dev, 0); handled = 1; } @@ -74,30 +87,41 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) handled = 1; } - if ( handled ) { - return IRQ_HANDLED; - } - return IRQ_NONE; + return (handled) ? IRQ_HANDLED : IRQ_NONE; } -int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) + +int mga_enable_vblank(drm_device_t *dev, int crtc) { - unsigned int cur_vblank; - int ret = 0; + drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - /* Assume that the user has missed the current sequence number - * by about a day rather than she wants to wait for years - * using vertical blanks... - */ - DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(&dev->vbl_received)) - - *sequence) <= (1 << 23))); + if (crtc != 0) { + DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", + crtc); + return 0; + } + + MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); + return 0; +} - *sequence = cur_vblank; - return ret; +void mga_disable_vblank(drm_device_t *dev, int crtc) +{ + if (crtc != 0) { + DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", + crtc); + } + + /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have + * a nice hardware counter that tracks the number of refreshes when + * the interrupt is disabled, and the kernel doesn't know the refresh + * rate to calculate an estimate. + */ + /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ } + int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -127,16 +151,25 @@ void mga_driver_irq_preinstall(drm_device_t * dev) MGA_WRITE(MGA_ICLEAR, ~0); } -void mga_driver_irq_postinstall(drm_device_t * dev) +int mga_driver_irq_postinstall(drm_device_t * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; + int ret; - DRM_INIT_WAITQUEUE( &dev_priv->fence_queue ); + ret = drm_vblank_init(dev, 1); + if (ret) + return ret; - /* Turn on vertical blank interrupt and soft trap interrupt. */ - MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); + DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); + + /* Turn on soft trap interrupt. Vertical blank interrupts are enabled + * in mga_enable_vblank. + */ + MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); + return 0; } + void mga_driver_irq_uninstall(drm_device_t * dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |