summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/mga_drv.c7
-rw-r--r--shared-core/mga_drv.h11
-rw-r--r--shared-core/mga_irq.c79
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;