11.2Sriastrad/* $NetBSD: mga_irq.c,v 1.3 2021/12/18 23:45:32 riastradh Exp $ */ 21.2Sriastrad 31.1Sriastrad/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- 41.1Sriastrad */ 51.1Sriastrad/* 61.1Sriastrad * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. 71.1Sriastrad * 81.1Sriastrad * The Weather Channel (TM) funded Tungsten Graphics to develop the 91.1Sriastrad * initial release of the Radeon 8500 driver under the XFree86 license. 101.1Sriastrad * This notice must be preserved. 111.1Sriastrad * 121.1Sriastrad * Permission is hereby granted, free of charge, to any person obtaining a 131.1Sriastrad * copy of this software and associated documentation files (the "Software"), 141.1Sriastrad * to deal in the Software without restriction, including without limitation 151.1Sriastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 161.1Sriastrad * and/or sell copies of the Software, and to permit persons to whom the 171.1Sriastrad * Software is furnished to do so, subject to the following conditions: 181.1Sriastrad * 191.1Sriastrad * The above copyright notice and this permission notice (including the next 201.1Sriastrad * paragraph) shall be included in all copies or substantial portions of the 211.1Sriastrad * Software. 221.1Sriastrad * 231.1Sriastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 241.1Sriastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 251.1Sriastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 261.1Sriastrad * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 271.1Sriastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 281.1Sriastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 291.1Sriastrad * DEALINGS IN THE SOFTWARE. 301.1Sriastrad * 311.1Sriastrad * Authors: 321.1Sriastrad * Keith Whitwell <keith@tungstengraphics.com> 331.1Sriastrad * Eric Anholt <anholt@FreeBSD.org> 341.1Sriastrad */ 351.1Sriastrad 361.2Sriastrad#include <sys/cdefs.h> 371.2Sriastrad__KERNEL_RCSID(0, "$NetBSD: mga_irq.c,v 1.3 2021/12/18 23:45:32 riastradh Exp $"); 381.2Sriastrad 391.1Sriastrad#include "mga_drv.h" 401.1Sriastrad 411.2Sriastradu32 mga_get_vblank_counter(struct drm_device *dev, unsigned int pipe) 421.1Sriastrad{ 431.1Sriastrad const drm_mga_private_t *const dev_priv = 441.1Sriastrad (drm_mga_private_t *) dev->dev_private; 451.1Sriastrad 461.2Sriastrad if (pipe != 0) 471.1Sriastrad return 0; 481.1Sriastrad 491.1Sriastrad return atomic_read(&dev_priv->vbl_received); 501.1Sriastrad} 511.1Sriastrad 521.1Sriastrad 531.2Sriastradirqreturn_t mga_driver_irq_handler(int irq, void *arg) 541.1Sriastrad{ 551.1Sriastrad struct drm_device *dev = (struct drm_device *) arg; 561.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 571.1Sriastrad int status; 581.1Sriastrad int handled = 0; 591.1Sriastrad 601.1Sriastrad status = MGA_READ(MGA_STATUS); 611.1Sriastrad 621.1Sriastrad /* VBLANK interrupt */ 631.1Sriastrad if (status & MGA_VLINEPEN) { 641.1Sriastrad MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); 651.1Sriastrad atomic_inc(&dev_priv->vbl_received); 661.1Sriastrad drm_handle_vblank(dev, 0); 671.1Sriastrad handled = 1; 681.1Sriastrad } 691.1Sriastrad 701.1Sriastrad /* SOFTRAP interrupt */ 711.1Sriastrad if (status & MGA_SOFTRAPEN) { 721.1Sriastrad const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); 731.1Sriastrad const u32 prim_end = MGA_READ(MGA_PRIMEND); 741.1Sriastrad 751.1Sriastrad 761.1Sriastrad MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); 771.1Sriastrad 781.1Sriastrad /* In addition to clearing the interrupt-pending bit, we 791.1Sriastrad * have to write to MGA_PRIMEND to re-start the DMA operation. 801.1Sriastrad */ 811.1Sriastrad if ((prim_start & ~0x03) != (prim_end & ~0x03)) 821.1Sriastrad MGA_WRITE(MGA_PRIMEND, prim_end); 831.1Sriastrad 841.1Sriastrad atomic_inc(&dev_priv->last_fence_retired); 851.2Sriastrad wake_up(&dev_priv->fence_queue); 861.1Sriastrad handled = 1; 871.1Sriastrad } 881.1Sriastrad 891.1Sriastrad if (handled) 901.1Sriastrad return IRQ_HANDLED; 911.1Sriastrad return IRQ_NONE; 921.1Sriastrad} 931.1Sriastrad 941.2Sriastradint mga_enable_vblank(struct drm_device *dev, unsigned int pipe) 951.1Sriastrad{ 961.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 971.1Sriastrad 981.2Sriastrad if (pipe != 0) { 991.2Sriastrad DRM_ERROR("tried to enable vblank on non-existent crtc %u\n", 1001.2Sriastrad pipe); 1011.1Sriastrad return 0; 1021.1Sriastrad } 1031.1Sriastrad 1041.1Sriastrad MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); 1051.1Sriastrad return 0; 1061.1Sriastrad} 1071.1Sriastrad 1081.1Sriastrad 1091.2Sriastradvoid mga_disable_vblank(struct drm_device *dev, unsigned int pipe) 1101.1Sriastrad{ 1111.2Sriastrad if (pipe != 0) { 1121.2Sriastrad DRM_ERROR("tried to disable vblank on non-existent crtc %u\n", 1131.2Sriastrad pipe); 1141.1Sriastrad } 1151.1Sriastrad 1161.1Sriastrad /* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have 1171.1Sriastrad * a nice hardware counter that tracks the number of refreshes when 1181.1Sriastrad * the interrupt is disabled, and the kernel doesn't know the refresh 1191.1Sriastrad * rate to calculate an estimate. 1201.1Sriastrad */ 1211.1Sriastrad /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ 1221.1Sriastrad} 1231.1Sriastrad 1241.3Sriastradvoid mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence) 1251.1Sriastrad{ 1261.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 1271.1Sriastrad unsigned int cur_fence; 1281.1Sriastrad 1291.1Sriastrad /* Assume that the user has missed the current sequence number 1301.1Sriastrad * by about a day rather than she wants to wait for years 1311.1Sriastrad * using fences. 1321.1Sriastrad */ 1331.3Sriastrad wait_event_timeout(dev_priv->fence_queue, 1341.1Sriastrad (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) 1351.3Sriastrad - *sequence) <= (1 << 23)), 1361.3Sriastrad msecs_to_jiffies(3000)); 1371.1Sriastrad 1381.1Sriastrad *sequence = cur_fence; 1391.1Sriastrad} 1401.1Sriastrad 1411.1Sriastradvoid mga_driver_irq_preinstall(struct drm_device *dev) 1421.1Sriastrad{ 1431.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 1441.1Sriastrad 1451.1Sriastrad /* Disable *all* interrupts */ 1461.1Sriastrad MGA_WRITE(MGA_IEN, 0); 1471.1Sriastrad /* Clear bits if they're already high */ 1481.1Sriastrad MGA_WRITE(MGA_ICLEAR, ~0); 1491.1Sriastrad} 1501.1Sriastrad 1511.1Sriastradint mga_driver_irq_postinstall(struct drm_device *dev) 1521.1Sriastrad{ 1531.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 1541.1Sriastrad 1551.2Sriastrad init_waitqueue_head(&dev_priv->fence_queue); 1561.1Sriastrad 1571.1Sriastrad /* Turn on soft trap interrupt. Vertical blank interrupts are enabled 1581.1Sriastrad * in mga_enable_vblank. 1591.1Sriastrad */ 1601.1Sriastrad MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN); 1611.1Sriastrad return 0; 1621.1Sriastrad} 1631.1Sriastrad 1641.1Sriastradvoid mga_driver_irq_uninstall(struct drm_device *dev) 1651.1Sriastrad{ 1661.1Sriastrad drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; 1671.1Sriastrad if (!dev_priv) 1681.1Sriastrad return; 1691.1Sriastrad 1701.1Sriastrad /* Disable *all* interrupts */ 1711.1Sriastrad MGA_WRITE(MGA_IEN, 0); 1721.1Sriastrad 1731.2Sriastrad dev->irq_enabled = false; 1741.1Sriastrad} 175