diff options
Diffstat (limited to 'drivers/gpu/drm/mga/mga_irq.c')
| -rw-r--r-- | drivers/gpu/drm/mga/mga_irq.c | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c index 9302cb8f0f8..1b071b8ff9d 100644 --- a/drivers/gpu/drm/mga/mga_irq.c +++ b/drivers/gpu/drm/mga/mga_irq.c @@ -1,5 +1,6 @@ /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- - * + */ +/* * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * * The Weather Channel (TM) funded Tungsten Graphics to develop the @@ -30,12 +31,23 @@ * Eric Anholt <anholt@FreeBSD.org> */ -#include "drmP.h" -#include "drm.h" -#include "mga_drm.h" +#include <drm/drmP.h> +#include <drm/mga_drm.h> #include "mga_drv.h" -irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) +u32 mga_get_vblank_counter(struct drm_device *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(int irq, void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -47,9 +59,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; } @@ -58,45 +69,56 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_end = MGA_READ(MGA_PRIMEND); + MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); /* In addition to clearing the interrupt-pending bit, we * have to write to MGA_PRIMEND to re-start the DMA operation. */ - if ((prim_start & ~0x03) != (prim_end & ~0x03)) { + if ((prim_start & ~0x03) != (prim_end & ~0x03)) MGA_WRITE(MGA_PRIMEND, prim_end); - } atomic_inc(&dev_priv->last_fence_retired); - DRM_WAKEUP(&dev_priv->fence_queue); + wake_up(&dev_priv->fence_queue); handled = 1; } - if (handled) { + if (handled) return IRQ_HANDLED; - } return IRQ_NONE; } -int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) +int mga_enable_vblank(struct drm_device *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; + } - *sequence = cur_vblank; + MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); + return 0; +} - return ret; + +void mga_disable_vblank(struct drm_device *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(struct drm_device * dev, unsigned int *sequence) +int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; unsigned int cur_fence; @@ -106,7 +128,7 @@ int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) * by about a day rather than she wants to wait for years * using fences. */ - DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ, + DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * HZ, (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) - *sequence) <= (1 << 23))); @@ -115,7 +137,7 @@ int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) return ret; } -void mga_driver_irq_preinstall(struct drm_device * dev) +void mga_driver_irq_preinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -125,17 +147,20 @@ void mga_driver_irq_preinstall(struct drm_device * dev) MGA_WRITE(MGA_ICLEAR, ~0); } -void mga_driver_irq_postinstall(struct drm_device * dev) +int mga_driver_irq_postinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); + init_waitqueue_head(&dev_priv->fence_queue); - /* Turn on vertical blank interrupt and soft trap interrupt. */ - MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); + /* 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(struct drm_device * dev) +void mga_driver_irq_uninstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; if (!dev_priv) @@ -144,5 +169,5 @@ void mga_driver_irq_uninstall(struct drm_device * dev) /* Disable *all* interrupts */ MGA_WRITE(MGA_IEN, 0); - dev->irq_enabled = 0; + dev->irq_enabled = false; } |
