1152909Sanholt/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- 2152909Sanholt */ 3139749Simp/*- 4112015Sanholt * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. 5145132Sanholt * 6112015Sanholt * The Weather Channel (TM) funded Tungsten Graphics to develop the 7112015Sanholt * initial release of the Radeon 8500 driver under the XFree86 license. 8112015Sanholt * This notice must be preserved. 9112015Sanholt * 10112015Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 11112015Sanholt * copy of this software and associated documentation files (the "Software"), 12112015Sanholt * to deal in the Software without restriction, including without limitation 13112015Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 14112015Sanholt * and/or sell copies of the Software, and to permit persons to whom the 15112015Sanholt * Software is furnished to do so, subject to the following conditions: 16112015Sanholt * 17112015Sanholt * The above copyright notice and this permission notice (including the next 18112015Sanholt * paragraph) shall be included in all copies or substantial portions of the 19112015Sanholt * Software. 20112015Sanholt * 21112015Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22112015Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23112015Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24112015Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25112015Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26112015Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27112015Sanholt * DEALINGS IN THE SOFTWARE. 28112015Sanholt * 29112015Sanholt * Authors: 30112015Sanholt * Keith Whitwell <keith@tungstengraphics.com> 31112015Sanholt * Eric Anholt <anholt@FreeBSD.org> 32112015Sanholt */ 33112015Sanholt 34152909Sanholt#include <sys/cdefs.h> 35152909Sanholt__FBSDID("$FreeBSD$"); 36152909Sanholt 37112015Sanholt#include "dev/drm/drmP.h" 38112015Sanholt#include "dev/drm/drm.h" 39112015Sanholt#include "dev/drm/mga_drm.h" 40112015Sanholt#include "dev/drm/mga_drv.h" 41112015Sanholt 42182080Srnolandu32 mga_get_vblank_counter(struct drm_device *dev, int crtc) 43182080Srnoland{ 44182080Srnoland const drm_mga_private_t *const dev_priv = 45182080Srnoland (drm_mga_private_t *) dev->dev_private; 46182080Srnoland 47182080Srnoland if (crtc != 0) { 48182080Srnoland return 0; 49182080Srnoland } 50182080Srnoland 51182080Srnoland 52182080Srnoland return atomic_read(&dev_priv->vbl_received); 53182080Srnoland} 54182080Srnoland 55182080Srnoland 56145132Sanholtirqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) 57112015Sanholt{ 58182080Srnoland struct drm_device *dev = (struct drm_device *) arg; 59145132Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 60112015Sanholt int status; 61152909Sanholt int handled = 0; 62112015Sanholt 63145132Sanholt status = MGA_READ(MGA_STATUS); 64145132Sanholt 65112015Sanholt /* VBLANK interrupt */ 66145132Sanholt if (status & MGA_VLINEPEN) { 67145132Sanholt MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); 68182080Srnoland atomic_inc(&dev_priv->vbl_received); 69182080Srnoland drm_handle_vblank(dev, 0); 70152909Sanholt handled = 1; 71152909Sanholt } 72152909Sanholt 73152909Sanholt /* SOFTRAP interrupt */ 74152909Sanholt if (status & MGA_SOFTRAPEN) { 75152909Sanholt const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); 76182080Srnoland const u32 prim_end = MGA_READ(MGA_PRIMEND); 77152909Sanholt 78152909Sanholt 79152909Sanholt MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); 80152909Sanholt 81152909Sanholt /* In addition to clearing the interrupt-pending bit, we 82152909Sanholt * have to write to MGA_PRIMEND to re-start the DMA operation. 83152909Sanholt */ 84182080Srnoland if ((prim_start & ~0x03) != (prim_end & ~0x03)) { 85152909Sanholt MGA_WRITE(MGA_PRIMEND, prim_end); 86152909Sanholt } 87152909Sanholt 88152909Sanholt atomic_inc(&dev_priv->last_fence_retired); 89152909Sanholt DRM_WAKEUP(&dev_priv->fence_queue); 90152909Sanholt handled = 1; 91152909Sanholt } 92152909Sanholt 93182080Srnoland if (handled) 94119098Sanholt return IRQ_HANDLED; 95119098Sanholt return IRQ_NONE; 96112015Sanholt} 97112015Sanholt 98182080Srnolandint mga_enable_vblank(struct drm_device *dev, int crtc) 99112015Sanholt{ 100182080Srnoland drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 101112015Sanholt 102182080Srnoland if (crtc != 0) { 103182080Srnoland DRM_ERROR("tried to enable vblank on non-existent crtc %d\n", 104182080Srnoland crtc); 105182080Srnoland return 0; 106182080Srnoland } 107112015Sanholt 108182080Srnoland MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); 109182080Srnoland return 0; 110182080Srnoland} 111112015Sanholt 112182080Srnoland 113182080Srnolandvoid mga_disable_vblank(struct drm_device *dev, int crtc) 114182080Srnoland{ 115182080Srnoland if (crtc != 0) { 116182080Srnoland DRM_ERROR("tried to disable vblank on non-existent crtc %d\n", 117182080Srnoland crtc); 118182080Srnoland } 119182080Srnoland 120182080Srnoland /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have 121182080Srnoland * a nice hardware counter that tracks the number of refreshes when 122182080Srnoland * the interrupt is disabled, and the kernel doesn't know the refresh 123182080Srnoland * rate to calculate an estimate. 124182080Srnoland */ 125182080Srnoland /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ 126112015Sanholt} 127112015Sanholt 128182080Srnolandint mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) 129152909Sanholt{ 130152909Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 131152909Sanholt unsigned int cur_fence; 132152909Sanholt int ret = 0; 133152909Sanholt 134152909Sanholt /* Assume that the user has missed the current sequence number 135152909Sanholt * by about a day rather than she wants to wait for years 136152909Sanholt * using fences. 137152909Sanholt */ 138152909Sanholt DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ, 139152909Sanholt (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) 140152909Sanholt - *sequence) <= (1 << 23))); 141152909Sanholt 142190023Srnoland if (ret == -ERESTART) 143190023Srnoland DRM_DEBUG("restarting syscall\n"); 144190023Srnoland 145152909Sanholt *sequence = cur_fence; 146152909Sanholt 147152909Sanholt return ret; 148152909Sanholt} 149152909Sanholt 150182080Srnolandvoid mga_driver_irq_preinstall(struct drm_device * dev) 151145132Sanholt{ 152145132Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 153112015Sanholt 154112015Sanholt /* Disable *all* interrupts */ 155145132Sanholt MGA_WRITE(MGA_IEN, 0); 156112015Sanholt /* Clear bits if they're already high */ 157145132Sanholt MGA_WRITE(MGA_ICLEAR, ~0); 158112015Sanholt} 159112015Sanholt 160182080Srnolandint mga_driver_irq_postinstall(struct drm_device * dev) 161145132Sanholt{ 162145132Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 163112015Sanholt 164182080Srnoland DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); 165182080Srnoland 166182080Srnoland /* Turn on soft trap interrupt. Vertical blank interrupts are enabled 167182080Srnoland * in mga_enable_vblank. 168182080Srnoland */ 169182080Srnoland MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); 170182080Srnoland return 0; 171112015Sanholt} 172112015Sanholt 173182080Srnolandvoid mga_driver_irq_uninstall(struct drm_device * dev) 174145132Sanholt{ 175145132Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 176119098Sanholt if (!dev_priv) 177119098Sanholt return; 178119098Sanholt 179119098Sanholt /* Disable *all* interrupts */ 180145132Sanholt MGA_WRITE(MGA_IEN, 0); 181182080Srnoland 182152909Sanholt dev->irq_enabled = 0; 183112015Sanholt} 184