Home | History | Annotate | Line # | Download | only in shared-core
      1 /* mach64_irq.c -- IRQ handling for ATI Mach64 -*- linux-c -*-
      2  * Created: Tue Feb 25, 2003 by Leif Delgass, based on radeon_irq.c/r128_irq.c
      3  */
      4 /*-
      5  * Copyright (C) The Weather Channel, Inc.  2002.
      6  * Copyright 2003 Leif Delgass
      7  * All Rights Reserved.
      8  *
      9  * The Weather Channel (TM) funded Tungsten Graphics to develop the
     10  * initial release of the Radeon 8500 driver under the XFree86 license.
     11  * This notice must be preserved.
     12  *
     13  * Permission is hereby granted, free of charge, to any person obtaining a
     14  * copy of this software and associated documentation files (the "Software"),
     15  * to deal in the Software without restriction, including without limitation
     16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     17  * and/or sell copies of the Software, and to permit persons to whom the
     18  * Software is furnished to do so, subject to the following conditions:
     19  *
     20  * The above copyright notice and this permission notice (including the next
     21  * paragraph) shall be included in all copies or substantial portions of the
     22  * Software.
     23  *
     24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     27  * THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     28  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     29  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     30  * DEALINGS IN THE SOFTWARE.
     31  *
     32  * Authors:
     33  *    Keith Whitwell <keith (at) tungstengraphics.com>
     34  *    Eric Anholt <anholt (at) FreeBSD.org>
     35  *    Leif Delgass <ldelgass (at) retinalburn.net>
     36  */
     37 
     38 #include "drmP.h"
     39 #include "drm.h"
     40 #include "mach64_drm.h"
     41 #include "mach64_drv.h"
     42 
     43 irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
     44 {
     45 	struct drm_device *dev = arg;
     46 	drm_mach64_private_t *dev_priv = dev->dev_private;
     47 	int status;
     48 
     49 	status = MACH64_READ(MACH64_CRTC_INT_CNTL);
     50 
     51 	/* VBLANK interrupt */
     52 	if (status & MACH64_CRTC_VBLANK_INT) {
     53 		/* Mask off all interrupt ack bits before setting the ack bit, since
     54 		 * there may be other handlers outside the DRM.
     55 		 *
     56 		 * NOTE: On mach64, you need to keep the enable bits set when doing
     57 		 * the ack, despite what the docs say about not acking and enabling
     58 		 * in a single write.
     59 		 */
     60 		MACH64_WRITE(MACH64_CRTC_INT_CNTL,
     61 			     (status & ~MACH64_CRTC_INT_ACKS)
     62 			     | MACH64_CRTC_VBLANK_INT);
     63 
     64 		atomic_inc(&dev_priv->vbl_received);
     65 		drm_handle_vblank(dev, 0);
     66 		return IRQ_HANDLED;
     67 	}
     68 	return IRQ_NONE;
     69 }
     70 
     71 u32 mach64_get_vblank_counter(struct drm_device * dev, unsigned int crtc)
     72 {
     73 	const drm_mach64_private_t *const dev_priv = dev->dev_private;
     74 
     75 	if (crtc != 0)
     76 		return 0;
     77 
     78 	return atomic_read(&dev_priv->vbl_received);
     79 }
     80 
     81 int mach64_enable_vblank(struct drm_device * dev, unsigned int crtc)
     82 {
     83 	drm_mach64_private_t *dev_priv = dev->dev_private;
     84 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
     85 
     86 	if (crtc != 0) {
     87 		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
     88 			  crtc);
     89 		return -EINVAL;
     90 	}
     91 
     92 	DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
     93 
     94 	/* Turn on VBLANK interrupt */
     95 	MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
     96 		     | MACH64_CRTC_VBLANK_INT_EN);
     97 
     98 	return 0;
     99 }
    100 
    101 void mach64_disable_vblank(struct drm_device * dev, unsigned int crtc)
    102 {
    103 	if (crtc != 0) {
    104 		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
    105 			  crtc);
    106 		return;
    107 	}
    108 
    109 	/*
    110 	 * FIXME: implement proper interrupt disable by using the vblank
    111 	 * counter register (if available).
    112 	 */
    113 }
    114 
    115 static void mach64_disable_vblank_local(struct drm_device * dev, unsigned int crtc)
    116 {
    117 	drm_mach64_private_t *dev_priv = dev->dev_private;
    118 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
    119 
    120 	if (crtc != 0) {
    121 		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
    122 			  crtc);
    123 		return;
    124 	}
    125 
    126 	DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
    127 
    128 	/* Disable and clear VBLANK interrupt */
    129 	MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
    130 		     | MACH64_CRTC_VBLANK_INT);
    131 }
    132 
    133 void mach64_driver_irq_preinstall(struct drm_device * dev)
    134 {
    135 	drm_mach64_private_t *dev_priv = dev->dev_private;
    136 
    137 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
    138 
    139 	DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
    140 
    141 	mach64_disable_vblank_local(dev, 0);
    142 }
    143 
    144 int mach64_driver_irq_postinstall(struct drm_device * dev)
    145 {
    146 	return 0;
    147 }
    148 
    149 void mach64_driver_irq_uninstall(struct drm_device * dev)
    150 {
    151 	drm_mach64_private_t *dev_priv = dev->dev_private;
    152 	if (!dev_priv)
    153 		return;
    154 
    155 	mach64_disable_vblank_local(dev, 0);
    156 
    157 	DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
    158 		  MACH64_READ(MACH64_CRTC_INT_CNTL));
    159 }
    160