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@tungstengraphics.com>
34  *    Eric Anholt <anholt@FreeBSD.org>
35  *    Leif Delgass <ldelgass@retinalburn.net>
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: stable/9/sys/dev/drm/mach64_irq.c 189130 2009-02-28 02:37:55Z rnoland $");
40 
41 #include "dev/drm/drmP.h"
42 #include "dev/drm/drm.h"
43 #include "dev/drm/mach64_drm.h"
44 #include "dev/drm/mach64_drv.h"
45 
mach64_driver_irq_handler(DRM_IRQ_ARGS)46 irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
47 {
48 	struct drm_device *dev = arg;
49 	drm_mach64_private_t *dev_priv = dev->dev_private;
50 	int status;
51 
52 	status = MACH64_READ(MACH64_CRTC_INT_CNTL);
53 
54 	/* VBLANK interrupt */
55 	if (status & MACH64_CRTC_VBLANK_INT) {
56 		/* Mask off all interrupt ack bits before setting the ack bit, since
57 		 * there may be other handlers outside the DRM.
58 		 *
59 		 * NOTE: On mach64, you need to keep the enable bits set when doing
60 		 * the ack, despite what the docs say about not acking and enabling
61 		 * in a single write.
62 		 */
63 		MACH64_WRITE(MACH64_CRTC_INT_CNTL,
64 			     (status & ~MACH64_CRTC_INT_ACKS)
65 			     | MACH64_CRTC_VBLANK_INT);
66 
67 		atomic_inc(&dev_priv->vbl_received);
68 		drm_handle_vblank(dev, 0);
69 		return IRQ_HANDLED;
70 	}
71 	return IRQ_NONE;
72 }
73 
mach64_get_vblank_counter(struct drm_device * dev,int crtc)74 u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc)
75 {
76 	const drm_mach64_private_t *const dev_priv = dev->dev_private;
77 
78 	if (crtc != 0)
79 		return 0;
80 
81 	return atomic_read(&dev_priv->vbl_received);
82 }
83 
mach64_enable_vblank(struct drm_device * dev,int crtc)84 int mach64_enable_vblank(struct drm_device * dev, int crtc)
85 {
86 	drm_mach64_private_t *dev_priv = dev->dev_private;
87 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
88 
89 	if (crtc != 0) {
90 		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
91 			  crtc);
92 		return -EINVAL;
93 	}
94 
95 	DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
96 
97 	/* Turn on VBLANK interrupt */
98 	MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
99 		     | MACH64_CRTC_VBLANK_INT_EN);
100 
101 	return 0;
102 }
103 
mach64_disable_vblank(struct drm_device * dev,int crtc)104 void mach64_disable_vblank(struct drm_device * dev, int crtc)
105 {
106 	if (crtc != 0) {
107 		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
108 			  crtc);
109 		return;
110 	}
111 
112 	/*
113 	 * FIXME: implement proper interrupt disable by using the vblank
114 	 * counter register (if available).
115 	 */
116 }
117 
mach64_disable_vblank_local(struct drm_device * dev,int crtc)118 static void mach64_disable_vblank_local(struct drm_device * dev, int crtc)
119 {
120 	drm_mach64_private_t *dev_priv = dev->dev_private;
121 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
122 
123 	if (crtc != 0) {
124 		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
125 			  crtc);
126 		return;
127 	}
128 
129 	DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
130 
131 	/* Disable and clear VBLANK interrupt */
132 	MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
133 		     | MACH64_CRTC_VBLANK_INT);
134 }
135 
mach64_driver_irq_preinstall(struct drm_device * dev)136 void mach64_driver_irq_preinstall(struct drm_device * dev)
137 {
138 	drm_mach64_private_t *dev_priv = dev->dev_private;
139 
140 	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
141 
142 	DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
143 
144 	mach64_disable_vblank_local(dev, 0);
145 }
146 
mach64_driver_irq_postinstall(struct drm_device * dev)147 int mach64_driver_irq_postinstall(struct drm_device * dev)
148 {
149 	return 0;
150 }
151 
mach64_driver_irq_uninstall(struct drm_device * dev)152 void mach64_driver_irq_uninstall(struct drm_device * dev)
153 {
154 	drm_mach64_private_t *dev_priv = dev->dev_private;
155 	if (!dev_priv)
156 		return;
157 
158 	mach64_disable_vblank_local(dev, 0);
159 
160 	DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
161 		  MACH64_READ(MACH64_CRTC_INT_CNTL));
162 }
163