1145132Sanholt/* mach64_irq.c -- IRQ handling for ATI Mach64 -*- linux-c -*-
2145132Sanholt * Created: Tue Feb 25, 2003 by Leif Delgass, based on radeon_irq.c/r128_irq.c
3152909Sanholt */
4152909Sanholt/*-
5145132Sanholt * Copyright (C) The Weather Channel, Inc.  2002.
6145132Sanholt * Copyright 2003 Leif Delgass
7145132Sanholt * All Rights Reserved.
8145132Sanholt *
9145132Sanholt * The Weather Channel (TM) funded Tungsten Graphics to develop the
10145132Sanholt * initial release of the Radeon 8500 driver under the XFree86 license.
11145132Sanholt * This notice must be preserved.
12145132Sanholt *
13145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
14145132Sanholt * copy of this software and associated documentation files (the "Software"),
15145132Sanholt * to deal in the Software without restriction, including without limitation
16145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
18145132Sanholt * Software is furnished to do so, subject to the following conditions:
19145132Sanholt *
20145132Sanholt * The above copyright notice and this permission notice (including the next
21145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
22145132Sanholt * Software.
23145132Sanholt *
24145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27145132Sanholt * THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30145132Sanholt * DEALINGS IN THE SOFTWARE.
31145132Sanholt *
32145132Sanholt * Authors:
33145132Sanholt *    Keith Whitwell <keith@tungstengraphics.com>
34145132Sanholt *    Eric Anholt <anholt@FreeBSD.org>
35145132Sanholt *    Leif Delgass <ldelgass@retinalburn.net>
36145132Sanholt */
37145132Sanholt
38152909Sanholt#include <sys/cdefs.h>
39152909Sanholt__FBSDID("$FreeBSD$");
40152909Sanholt
41145132Sanholt#include "dev/drm/drmP.h"
42145132Sanholt#include "dev/drm/drm.h"
43145132Sanholt#include "dev/drm/mach64_drm.h"
44145132Sanholt#include "dev/drm/mach64_drv.h"
45145132Sanholt
46145132Sanholtirqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
47145132Sanholt{
48182080Srnoland	struct drm_device *dev = arg;
49182080Srnoland	drm_mach64_private_t *dev_priv = dev->dev_private;
50145132Sanholt	int status;
51145132Sanholt
52145132Sanholt	status = MACH64_READ(MACH64_CRTC_INT_CNTL);
53145132Sanholt
54145132Sanholt	/* VBLANK interrupt */
55145132Sanholt	if (status & MACH64_CRTC_VBLANK_INT) {
56145132Sanholt		/* Mask off all interrupt ack bits before setting the ack bit, since
57145132Sanholt		 * there may be other handlers outside the DRM.
58145132Sanholt		 *
59145132Sanholt		 * NOTE: On mach64, you need to keep the enable bits set when doing
60145132Sanholt		 * the ack, despite what the docs say about not acking and enabling
61145132Sanholt		 * in a single write.
62145132Sanholt		 */
63145132Sanholt		MACH64_WRITE(MACH64_CRTC_INT_CNTL,
64145132Sanholt			     (status & ~MACH64_CRTC_INT_ACKS)
65145132Sanholt			     | MACH64_CRTC_VBLANK_INT);
66145132Sanholt
67182080Srnoland		atomic_inc(&dev_priv->vbl_received);
68182080Srnoland		drm_handle_vblank(dev, 0);
69145132Sanholt		return IRQ_HANDLED;
70145132Sanholt	}
71145132Sanholt	return IRQ_NONE;
72145132Sanholt}
73145132Sanholt
74182080Srnolandu32 mach64_get_vblank_counter(struct drm_device * dev, int crtc)
75145132Sanholt{
76182080Srnoland	const drm_mach64_private_t *const dev_priv = dev->dev_private;
77145132Sanholt
78182080Srnoland	if (crtc != 0)
79182080Srnoland		return 0;
80145132Sanholt
81182080Srnoland	return atomic_read(&dev_priv->vbl_received);
82182080Srnoland}
83145132Sanholt
84182080Srnolandint mach64_enable_vblank(struct drm_device * dev, int crtc)
85182080Srnoland{
86182080Srnoland	drm_mach64_private_t *dev_priv = dev->dev_private;
87182080Srnoland	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
88182080Srnoland
89182080Srnoland	if (crtc != 0) {
90182080Srnoland		DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
91182080Srnoland			  crtc);
92182080Srnoland		return -EINVAL;
93182080Srnoland	}
94182080Srnoland
95182080Srnoland	DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
96182080Srnoland
97182080Srnoland	/* Turn on VBLANK interrupt */
98182080Srnoland	MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
99182080Srnoland		     | MACH64_CRTC_VBLANK_INT_EN);
100182080Srnoland
101182080Srnoland	return 0;
102145132Sanholt}
103145132Sanholt
104182080Srnolandvoid mach64_disable_vblank(struct drm_device * dev, int crtc)
105145132Sanholt{
106182080Srnoland	if (crtc != 0) {
107182080Srnoland		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
108182080Srnoland			  crtc);
109182080Srnoland		return;
110182080Srnoland	}
111145132Sanholt
112182080Srnoland	/*
113182080Srnoland	 * FIXME: implement proper interrupt disable by using the vblank
114182080Srnoland	 * counter register (if available).
115182080Srnoland	 */
116182080Srnoland}
117182080Srnoland
118182080Srnolandstatic void mach64_disable_vblank_local(struct drm_device * dev, int crtc)
119182080Srnoland{
120182080Srnoland	drm_mach64_private_t *dev_priv = dev->dev_private;
121145132Sanholt	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
122145132Sanholt
123182080Srnoland	if (crtc != 0) {
124182080Srnoland		DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
125182080Srnoland			  crtc);
126182080Srnoland		return;
127182080Srnoland	}
128145132Sanholt
129182080Srnoland	DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
130182080Srnoland
131145132Sanholt	/* Disable and clear VBLANK interrupt */
132145132Sanholt	MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
133145132Sanholt		     | MACH64_CRTC_VBLANK_INT);
134145132Sanholt}
135145132Sanholt
136182080Srnolandvoid mach64_driver_irq_preinstall(struct drm_device * dev)
137145132Sanholt{
138182080Srnoland	drm_mach64_private_t *dev_priv = dev->dev_private;
139145132Sanholt
140182080Srnoland	u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
141145132Sanholt
142182080Srnoland	DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
143145132Sanholt
144182080Srnoland	mach64_disable_vblank_local(dev, 0);
145145132Sanholt}
146145132Sanholt
147182080Srnolandint mach64_driver_irq_postinstall(struct drm_device * dev)
148145132Sanholt{
149189130Srnoland	return 0;
150182080Srnoland}
151182080Srnoland
152182080Srnolandvoid mach64_driver_irq_uninstall(struct drm_device * dev)
153182080Srnoland{
154182080Srnoland	drm_mach64_private_t *dev_priv = dev->dev_private;
155145132Sanholt	if (!dev_priv)
156145132Sanholt		return;
157145132Sanholt
158182080Srnoland	mach64_disable_vblank_local(dev, 0);
159145132Sanholt
160145132Sanholt	DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
161145132Sanholt		  MACH64_READ(MACH64_CRTC_INT_CNTL));
162145132Sanholt}
163