Back to home page

OSCL-LXR

 
 

    


0001 /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
0002  */
0003 /*
0004  * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
0005  *
0006  * The Weather Channel (TM) funded Tungsten Graphics to develop the
0007  * initial release of the Radeon 8500 driver under the XFree86 license.
0008  * This notice must be preserved.
0009  *
0010  * Permission is hereby granted, free of charge, to any person obtaining a
0011  * copy of this software and associated documentation files (the "Software"),
0012  * to deal in the Software without restriction, including without limitation
0013  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0014  * and/or sell copies of the Software, and to permit persons to whom the
0015  * Software is furnished to do so, subject to the following conditions:
0016  *
0017  * The above copyright notice and this permission notice (including the next
0018  * paragraph) shall be included in all copies or substantial portions of the
0019  * Software.
0020  *
0021  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0022  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0023  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0024  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
0025  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0026  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0027  * DEALINGS IN THE SOFTWARE.
0028  *
0029  * Authors:
0030  *    Keith Whitwell <keith@tungstengraphics.com>
0031  *    Eric Anholt <anholt@FreeBSD.org>
0032  */
0033 
0034 #include "mga_drv.h"
0035 
0036 u32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
0037 {
0038     const drm_mga_private_t *const dev_priv =
0039         (drm_mga_private_t *) dev->dev_private;
0040 
0041     if (pipe != 0)
0042         return 0;
0043 
0044     return atomic_read(&dev_priv->vbl_received);
0045 }
0046 
0047 
0048 irqreturn_t mga_driver_irq_handler(int irq, void *arg)
0049 {
0050     struct drm_device *dev = (struct drm_device *) arg;
0051     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0052     int status;
0053     int handled = 0;
0054 
0055     status = MGA_READ(MGA_STATUS);
0056 
0057     /* VBLANK interrupt */
0058     if (status & MGA_VLINEPEN) {
0059         MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
0060         atomic_inc(&dev_priv->vbl_received);
0061         drm_handle_vblank(dev, 0);
0062         handled = 1;
0063     }
0064 
0065     /* SOFTRAP interrupt */
0066     if (status & MGA_SOFTRAPEN) {
0067         const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
0068         const u32 prim_end = MGA_READ(MGA_PRIMEND);
0069 
0070 
0071         MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
0072 
0073         /* In addition to clearing the interrupt-pending bit, we
0074          * have to write to MGA_PRIMEND to re-start the DMA operation.
0075          */
0076         if ((prim_start & ~0x03) != (prim_end & ~0x03))
0077             MGA_WRITE(MGA_PRIMEND, prim_end);
0078 
0079         atomic_inc(&dev_priv->last_fence_retired);
0080         wake_up(&dev_priv->fence_queue);
0081         handled = 1;
0082     }
0083 
0084     if (handled)
0085         return IRQ_HANDLED;
0086     return IRQ_NONE;
0087 }
0088 
0089 int mga_enable_vblank(struct drm_device *dev, unsigned int pipe)
0090 {
0091     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0092 
0093     if (pipe != 0) {
0094         DRM_ERROR("tried to enable vblank on non-existent crtc %u\n",
0095               pipe);
0096         return 0;
0097     }
0098 
0099     MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
0100     return 0;
0101 }
0102 
0103 
0104 void mga_disable_vblank(struct drm_device *dev, unsigned int pipe)
0105 {
0106     if (pipe != 0) {
0107         DRM_ERROR("tried to disable vblank on non-existent crtc %u\n",
0108               pipe);
0109     }
0110 
0111     /* Do *NOT* disable the vertical refresh interrupt.  MGA doesn't have
0112      * a nice hardware counter that tracks the number of refreshes when
0113      * the interrupt is disabled, and the kernel doesn't know the refresh
0114      * rate to calculate an estimate.
0115      */
0116     /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
0117 }
0118 
0119 void mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence)
0120 {
0121     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0122     unsigned int cur_fence;
0123 
0124     /* Assume that the user has missed the current sequence number
0125      * by about a day rather than she wants to wait for years
0126      * using fences.
0127      */
0128     wait_event_timeout(dev_priv->fence_queue,
0129             (((cur_fence = atomic_read(&dev_priv->last_fence_retired))
0130               - *sequence) <= (1 << 23)),
0131             msecs_to_jiffies(3000));
0132 
0133     *sequence = cur_fence;
0134 }
0135 
0136 void mga_driver_irq_preinstall(struct drm_device *dev)
0137 {
0138     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0139 
0140     /* Disable *all* interrupts */
0141     MGA_WRITE(MGA_IEN, 0);
0142     /* Clear bits if they're already high */
0143     MGA_WRITE(MGA_ICLEAR, ~0);
0144 }
0145 
0146 int mga_driver_irq_postinstall(struct drm_device *dev)
0147 {
0148     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0149 
0150     init_waitqueue_head(&dev_priv->fence_queue);
0151 
0152     /* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
0153      * in mga_enable_vblank.
0154      */
0155     MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
0156     return 0;
0157 }
0158 
0159 void mga_driver_irq_uninstall(struct drm_device *dev)
0160 {
0161     drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
0162     if (!dev_priv)
0163         return;
0164 
0165     /* Disable *all* interrupts */
0166     MGA_WRITE(MGA_IEN, 0);
0167 
0168     dev->irq_enabled = false;
0169 }