18c2ecf20Sopenharmony_ci/* via_irq.c 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright 2004 BEAM Ltd. 48c2ecf20Sopenharmony_ci * Copyright 2002 Tungsten Graphics, Inc. 58c2ecf20Sopenharmony_ci * Copyright 2005 Thomas Hellstrom. 68c2ecf20Sopenharmony_ci * All Rights Reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 98c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 108c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 118c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 128c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 138c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 168c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 178c2ecf20Sopenharmony_ci * Software. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 208c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 218c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 228c2ecf20Sopenharmony_ci * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 238c2ecf20Sopenharmony_ci * DAMAGES OR 248c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 258c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 268c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Authors: 298c2ecf20Sopenharmony_ci * Terry Barnaby <terry1@beam.ltd.uk> 308c2ecf20Sopenharmony_ci * Keith Whitwell <keith@tungstengraphics.com> 318c2ecf20Sopenharmony_ci * Thomas Hellstrom <unichrome@shipmail.org> 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank 348c2ecf20Sopenharmony_ci * interrupt, as well as an infrastructure to handle other interrupts of the chip. 358c2ecf20Sopenharmony_ci * The refresh rate is also calculated for video playback sync purposes. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 398c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 408c2ecf20Sopenharmony_ci#include <drm/via_drm.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include "via_drv.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define VIA_REG_INTERRUPT 0x200 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* VIA_REG_INTERRUPT */ 478c2ecf20Sopenharmony_ci#define VIA_IRQ_GLOBAL (1 << 31) 488c2ecf20Sopenharmony_ci#define VIA_IRQ_VBLANK_ENABLE (1 << 19) 498c2ecf20Sopenharmony_ci#define VIA_IRQ_VBLANK_PENDING (1 << 3) 508c2ecf20Sopenharmony_ci#define VIA_IRQ_HQV0_ENABLE (1 << 11) 518c2ecf20Sopenharmony_ci#define VIA_IRQ_HQV1_ENABLE (1 << 25) 528c2ecf20Sopenharmony_ci#define VIA_IRQ_HQV0_PENDING (1 << 9) 538c2ecf20Sopenharmony_ci#define VIA_IRQ_HQV1_PENDING (1 << 10) 548c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20) 558c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21) 568c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22) 578c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23) 588c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA0_DD_PENDING (1 << 4) 598c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA0_TD_PENDING (1 << 5) 608c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA1_DD_PENDING (1 << 6) 618c2ecf20Sopenharmony_ci#define VIA_IRQ_DMA1_TD_PENDING (1 << 7) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * Device-specific IRQs go here. This type might need to be extended with 668c2ecf20Sopenharmony_ci * the register if there are multiple IRQ control registers. 678c2ecf20Sopenharmony_ci * Currently we activate the HQV interrupts of Unichrome Pro group A. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic maskarray_t via_pro_group_a_irqs[] = { 718c2ecf20Sopenharmony_ci {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 728c2ecf20Sopenharmony_ci 0x00000000 }, 738c2ecf20Sopenharmony_ci {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 748c2ecf20Sopenharmony_ci 0x00000000 }, 758c2ecf20Sopenharmony_ci {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, 768c2ecf20Sopenharmony_ci VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, 778c2ecf20Sopenharmony_ci {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, 788c2ecf20Sopenharmony_ci VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_cistatic int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs); 818c2ecf20Sopenharmony_cistatic int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic maskarray_t via_unichrome_irqs[] = { 848c2ecf20Sopenharmony_ci {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0, 858c2ecf20Sopenharmony_ci VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}, 868c2ecf20Sopenharmony_ci {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1, 878c2ecf20Sopenharmony_ci VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008} 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_cistatic int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs); 908c2ecf20Sopenharmony_cistatic int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciu32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = dev->dev_private; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (pipe != 0) 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return atomic_read(&dev_priv->vbl_received); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciirqreturn_t via_driver_irq_handler(int irq, void *arg) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct drm_device *dev = (struct drm_device *) arg; 1068c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 1078c2ecf20Sopenharmony_ci u32 status; 1088c2ecf20Sopenharmony_ci int handled = 0; 1098c2ecf20Sopenharmony_ci ktime_t cur_vblank; 1108c2ecf20Sopenharmony_ci drm_via_irq_t *cur_irq = dev_priv->via_irqs; 1118c2ecf20Sopenharmony_ci int i; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 1148c2ecf20Sopenharmony_ci if (status & VIA_IRQ_VBLANK_PENDING) { 1158c2ecf20Sopenharmony_ci atomic_inc(&dev_priv->vbl_received); 1168c2ecf20Sopenharmony_ci if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) { 1178c2ecf20Sopenharmony_ci cur_vblank = ktime_get(); 1188c2ecf20Sopenharmony_ci if (dev_priv->last_vblank_valid) { 1198c2ecf20Sopenharmony_ci dev_priv->nsec_per_vblank = 1208c2ecf20Sopenharmony_ci ktime_sub(cur_vblank, 1218c2ecf20Sopenharmony_ci dev_priv->last_vblank) >> 4; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci dev_priv->last_vblank = cur_vblank; 1248c2ecf20Sopenharmony_ci dev_priv->last_vblank_valid = 1; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) { 1278c2ecf20Sopenharmony_ci DRM_DEBUG("nsec per vblank is: %llu\n", 1288c2ecf20Sopenharmony_ci ktime_to_ns(dev_priv->nsec_per_vblank)); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci drm_handle_vblank(dev, 0); 1318c2ecf20Sopenharmony_ci handled = 1; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci for (i = 0; i < dev_priv->num_irqs; ++i) { 1358c2ecf20Sopenharmony_ci if (status & cur_irq->pending_mask) { 1368c2ecf20Sopenharmony_ci atomic_inc(&cur_irq->irq_received); 1378c2ecf20Sopenharmony_ci wake_up(&cur_irq->irq_queue); 1388c2ecf20Sopenharmony_ci handled = 1; 1398c2ecf20Sopenharmony_ci if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) 1408c2ecf20Sopenharmony_ci via_dmablit_handler(dev, 0, 1); 1418c2ecf20Sopenharmony_ci else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) 1428c2ecf20Sopenharmony_ci via_dmablit_handler(dev, 1, 1); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci cur_irq++; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* Acknowledge interrupts */ 1488c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (handled) 1528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci return IRQ_NONE; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci u32 status; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (dev_priv) { 1628c2ecf20Sopenharmony_ci /* Acknowledge interrupts */ 1638c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 1648c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status | 1658c2ecf20Sopenharmony_ci dev_priv->irq_pending_mask); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciint via_enable_vblank(struct drm_device *dev, unsigned int pipe) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = dev->dev_private; 1728c2ecf20Sopenharmony_ci u32 status; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (pipe != 0) { 1758c2ecf20Sopenharmony_ci DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); 1768c2ecf20Sopenharmony_ci return -EINVAL; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 1808c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci via_write8(dev_priv, 0x83d4, 0x11); 1838c2ecf20Sopenharmony_ci via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_civoid via_disable_vblank(struct drm_device *dev, unsigned int pipe) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = dev->dev_private; 1918c2ecf20Sopenharmony_ci u32 status; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 1948c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci via_write8(dev_priv, 0x83d4, 0x11); 1978c2ecf20Sopenharmony_ci via_write8_mask(dev_priv, 0x83d5, 0x30, 0); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (pipe != 0) 2008c2ecf20Sopenharmony_ci DRM_ERROR("%s: bad crtc %u\n", __func__, pipe); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int 2048c2ecf20Sopenharmony_civia_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence, 2058c2ecf20Sopenharmony_ci unsigned int *sequence) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 2088c2ecf20Sopenharmony_ci unsigned int cur_irq_sequence; 2098c2ecf20Sopenharmony_ci drm_via_irq_t *cur_irq; 2108c2ecf20Sopenharmony_ci int ret = 0; 2118c2ecf20Sopenharmony_ci maskarray_t *masks; 2128c2ecf20Sopenharmony_ci int real_irq; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci DRM_DEBUG("\n"); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (!dev_priv) { 2178c2ecf20Sopenharmony_ci DRM_ERROR("called with no initialization\n"); 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (irq >= drm_via_irq_num) { 2228c2ecf20Sopenharmony_ci DRM_ERROR("Trying to wait on unknown irq %d\n", irq); 2238c2ecf20Sopenharmony_ci return -EINVAL; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci real_irq = dev_priv->irq_map[irq]; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (real_irq < 0) { 2298c2ecf20Sopenharmony_ci DRM_ERROR("Video IRQ %d not available on this hardware.\n", 2308c2ecf20Sopenharmony_ci irq); 2318c2ecf20Sopenharmony_ci return -EINVAL; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci masks = dev_priv->irq_masks; 2358c2ecf20Sopenharmony_ci cur_irq = dev_priv->via_irqs + real_irq; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (masks[real_irq][2] && !force_sequence) { 2388c2ecf20Sopenharmony_ci VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, 2398c2ecf20Sopenharmony_ci ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) == 2408c2ecf20Sopenharmony_ci masks[irq][4])); 2418c2ecf20Sopenharmony_ci cur_irq_sequence = atomic_read(&cur_irq->irq_received); 2428c2ecf20Sopenharmony_ci } else { 2438c2ecf20Sopenharmony_ci VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ, 2448c2ecf20Sopenharmony_ci (((cur_irq_sequence = 2458c2ecf20Sopenharmony_ci atomic_read(&cur_irq->irq_received)) - 2468c2ecf20Sopenharmony_ci *sequence) <= (1 << 23))); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci *sequence = cur_irq_sequence; 2498c2ecf20Sopenharmony_ci return ret; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* 2548c2ecf20Sopenharmony_ci * drm_dma.h hooks 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_civoid via_driver_irq_preinstall(struct drm_device *dev) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 2608c2ecf20Sopenharmony_ci u32 status; 2618c2ecf20Sopenharmony_ci drm_via_irq_t *cur_irq; 2628c2ecf20Sopenharmony_ci int i; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci DRM_DEBUG("dev_priv: %p\n", dev_priv); 2658c2ecf20Sopenharmony_ci if (dev_priv) { 2668c2ecf20Sopenharmony_ci cur_irq = dev_priv->via_irqs; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; 2698c2ecf20Sopenharmony_ci dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (dev_priv->chipset == VIA_PRO_GROUP_A || 2728c2ecf20Sopenharmony_ci dev_priv->chipset == VIA_DX9_0) { 2738c2ecf20Sopenharmony_ci dev_priv->irq_masks = via_pro_group_a_irqs; 2748c2ecf20Sopenharmony_ci dev_priv->num_irqs = via_num_pro_group_a; 2758c2ecf20Sopenharmony_ci dev_priv->irq_map = via_irqmap_pro_group_a; 2768c2ecf20Sopenharmony_ci } else { 2778c2ecf20Sopenharmony_ci dev_priv->irq_masks = via_unichrome_irqs; 2788c2ecf20Sopenharmony_ci dev_priv->num_irqs = via_num_unichrome; 2798c2ecf20Sopenharmony_ci dev_priv->irq_map = via_irqmap_unichrome; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < dev_priv->num_irqs; ++i) { 2838c2ecf20Sopenharmony_ci atomic_set(&cur_irq->irq_received, 0); 2848c2ecf20Sopenharmony_ci cur_irq->enable_mask = dev_priv->irq_masks[i][0]; 2858c2ecf20Sopenharmony_ci cur_irq->pending_mask = dev_priv->irq_masks[i][1]; 2868c2ecf20Sopenharmony_ci init_waitqueue_head(&cur_irq->irq_queue); 2878c2ecf20Sopenharmony_ci dev_priv->irq_enable_mask |= cur_irq->enable_mask; 2888c2ecf20Sopenharmony_ci dev_priv->irq_pending_mask |= cur_irq->pending_mask; 2898c2ecf20Sopenharmony_ci cur_irq++; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci DRM_DEBUG("Initializing IRQ %d\n", i); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci dev_priv->last_vblank_valid = 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Clear VSync interrupt regs */ 2978c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 2988c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status & 2998c2ecf20Sopenharmony_ci ~(dev_priv->irq_enable_mask)); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Clear bits if they're already high */ 3028c2ecf20Sopenharmony_ci viadrv_acknowledge_irqs(dev_priv); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciint via_driver_irq_postinstall(struct drm_device *dev) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 3098c2ecf20Sopenharmony_ci u32 status; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci DRM_DEBUG("via_driver_irq_postinstall\n"); 3128c2ecf20Sopenharmony_ci if (!dev_priv) 3138c2ecf20Sopenharmony_ci return -EINVAL; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 3168c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL 3178c2ecf20Sopenharmony_ci | dev_priv->irq_enable_mask); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Some magic, oh for some data sheets ! */ 3208c2ecf20Sopenharmony_ci via_write8(dev_priv, 0x83d4, 0x11); 3218c2ecf20Sopenharmony_ci via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_civoid via_driver_irq_uninstall(struct drm_device *dev) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 3298c2ecf20Sopenharmony_ci u32 status; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci DRM_DEBUG("\n"); 3328c2ecf20Sopenharmony_ci if (dev_priv) { 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Some more magic, oh for some data sheets ! */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci via_write8(dev_priv, 0x83d4, 0x11); 3378c2ecf20Sopenharmony_ci via_write8_mask(dev_priv, 0x83d5, 0x30, 0); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci status = via_read(dev_priv, VIA_REG_INTERRUPT); 3408c2ecf20Sopenharmony_ci via_write(dev_priv, VIA_REG_INTERRUPT, status & 3418c2ecf20Sopenharmony_ci ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask)); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ciint via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci drm_via_irqwait_t *irqwait = data; 3488c2ecf20Sopenharmony_ci struct timespec64 now; 3498c2ecf20Sopenharmony_ci int ret = 0; 3508c2ecf20Sopenharmony_ci drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 3518c2ecf20Sopenharmony_ci drm_via_irq_t *cur_irq = dev_priv->via_irqs; 3528c2ecf20Sopenharmony_ci int force_sequence; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (irqwait->request.irq >= dev_priv->num_irqs) { 3558c2ecf20Sopenharmony_ci DRM_ERROR("Trying to wait on unknown irq %d\n", 3568c2ecf20Sopenharmony_ci irqwait->request.irq); 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci cur_irq += irqwait->request.irq; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) { 3638c2ecf20Sopenharmony_ci case VIA_IRQ_RELATIVE: 3648c2ecf20Sopenharmony_ci irqwait->request.sequence += 3658c2ecf20Sopenharmony_ci atomic_read(&cur_irq->irq_received); 3668c2ecf20Sopenharmony_ci irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; 3678c2ecf20Sopenharmony_ci case VIA_IRQ_ABSOLUTE: 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci default: 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (irqwait->request.type & VIA_IRQ_SIGNAL) { 3748c2ecf20Sopenharmony_ci DRM_ERROR("Signals on Via IRQs not implemented yet.\n"); 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence, 3818c2ecf20Sopenharmony_ci &irqwait->request.sequence); 3828c2ecf20Sopenharmony_ci ktime_get_ts64(&now); 3838c2ecf20Sopenharmony_ci irqwait->reply.tval_sec = now.tv_sec; 3848c2ecf20Sopenharmony_ci irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci} 388