Back to home page

OSCL-LXR

 
 

    


0001 /* via_irq.c
0002  *
0003  * Copyright 2004 BEAM Ltd.
0004  * Copyright 2002 Tungsten Graphics, Inc.
0005  * Copyright 2005 Thomas Hellstrom.
0006  * All Rights Reserved.
0007  *
0008  * Permission is hereby granted, free of charge, to any person obtaining a
0009  * copy of this software and associated documentation files (the "Software"),
0010  * to deal in the Software without restriction, including without limitation
0011  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0012  * and/or sell copies of the Software, and to permit persons to whom the
0013  * Software is furnished to do so, subject to the following conditions:
0014  *
0015  * The above copyright notice and this permission notice (including the next
0016  * paragraph) shall be included in all copies or substantial portions of the
0017  * Software.
0018  *
0019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0022  * BEAM LTD, TUNGSTEN GRAPHICS  AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
0023  * DAMAGES OR
0024  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0025  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0026  * DEALINGS IN THE SOFTWARE.
0027  *
0028  * Authors:
0029  *    Terry Barnaby <terry1@beam.ltd.uk>
0030  *    Keith Whitwell <keith@tungstengraphics.com>
0031  *    Thomas Hellstrom <unichrome@shipmail.org>
0032  *
0033  * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
0034  * interrupt, as well as an infrastructure to handle other interrupts of the chip.
0035  * The refresh rate is also calculated for video playback sync purposes.
0036  */
0037 
0038 #include <drm/drm_device.h>
0039 #include <drm/drm_vblank.h>
0040 #include <drm/via_drm.h>
0041 
0042 #include "via_drv.h"
0043 
0044 #define VIA_REG_INTERRUPT       0x200
0045 
0046 /* VIA_REG_INTERRUPT */
0047 #define VIA_IRQ_GLOBAL    (1 << 31)
0048 #define VIA_IRQ_VBLANK_ENABLE   (1 << 19)
0049 #define VIA_IRQ_VBLANK_PENDING  (1 << 3)
0050 #define VIA_IRQ_HQV0_ENABLE     (1 << 11)
0051 #define VIA_IRQ_HQV1_ENABLE     (1 << 25)
0052 #define VIA_IRQ_HQV0_PENDING    (1 << 9)
0053 #define VIA_IRQ_HQV1_PENDING    (1 << 10)
0054 #define VIA_IRQ_DMA0_DD_ENABLE  (1 << 20)
0055 #define VIA_IRQ_DMA0_TD_ENABLE  (1 << 21)
0056 #define VIA_IRQ_DMA1_DD_ENABLE  (1 << 22)
0057 #define VIA_IRQ_DMA1_TD_ENABLE  (1 << 23)
0058 #define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
0059 #define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
0060 #define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
0061 #define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
0062 
0063 
0064 /*
0065  * Device-specific IRQs go here. This type might need to be extended with
0066  * the register if there are multiple IRQ control registers.
0067  * Currently we activate the HQV interrupts of  Unichrome Pro group A.
0068  */
0069 
0070 static maskarray_t via_pro_group_a_irqs[] = {
0071     {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
0072      0x00000000 },
0073     {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
0074      0x00000000 },
0075     {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
0076      VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
0077     {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
0078      VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
0079 };
0080 static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
0081 static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
0082 
0083 static maskarray_t via_unichrome_irqs[] = {
0084     {VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
0085      VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
0086     {VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
0087      VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
0088 };
0089 static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
0090 static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
0091 
0092 
0093 u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
0094 {
0095     drm_via_private_t *dev_priv = dev->dev_private;
0096 
0097     if (pipe != 0)
0098         return 0;
0099 
0100     return atomic_read(&dev_priv->vbl_received);
0101 }
0102 
0103 irqreturn_t via_driver_irq_handler(int irq, void *arg)
0104 {
0105     struct drm_device *dev = (struct drm_device *) arg;
0106     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0107     u32 status;
0108     int handled = 0;
0109     ktime_t cur_vblank;
0110     drm_via_irq_t *cur_irq = dev_priv->via_irqs;
0111     int i;
0112 
0113     status = via_read(dev_priv, VIA_REG_INTERRUPT);
0114     if (status & VIA_IRQ_VBLANK_PENDING) {
0115         atomic_inc(&dev_priv->vbl_received);
0116         if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
0117             cur_vblank = ktime_get();
0118             if (dev_priv->last_vblank_valid) {
0119                 dev_priv->nsec_per_vblank =
0120                     ktime_sub(cur_vblank,
0121                         dev_priv->last_vblank) >> 4;
0122             }
0123             dev_priv->last_vblank = cur_vblank;
0124             dev_priv->last_vblank_valid = 1;
0125         }
0126         if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
0127             DRM_DEBUG("nsec per vblank is: %llu\n",
0128                   ktime_to_ns(dev_priv->nsec_per_vblank));
0129         }
0130         drm_handle_vblank(dev, 0);
0131         handled = 1;
0132     }
0133 
0134     for (i = 0; i < dev_priv->num_irqs; ++i) {
0135         if (status & cur_irq->pending_mask) {
0136             atomic_inc(&cur_irq->irq_received);
0137             wake_up(&cur_irq->irq_queue);
0138             handled = 1;
0139             if (dev_priv->irq_map[drm_via_irq_dma0_td] == i)
0140                 via_dmablit_handler(dev, 0, 1);
0141             else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i)
0142                 via_dmablit_handler(dev, 1, 1);
0143         }
0144         cur_irq++;
0145     }
0146 
0147     /* Acknowledge interrupts */
0148     via_write(dev_priv, VIA_REG_INTERRUPT, status);
0149 
0150 
0151     if (handled)
0152         return IRQ_HANDLED;
0153     else
0154         return IRQ_NONE;
0155 }
0156 
0157 static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv)
0158 {
0159     u32 status;
0160 
0161     if (dev_priv) {
0162         /* Acknowledge interrupts */
0163         status = via_read(dev_priv, VIA_REG_INTERRUPT);
0164         via_write(dev_priv, VIA_REG_INTERRUPT, status |
0165               dev_priv->irq_pending_mask);
0166     }
0167 }
0168 
0169 int via_enable_vblank(struct drm_device *dev, unsigned int pipe)
0170 {
0171     drm_via_private_t *dev_priv = dev->dev_private;
0172     u32 status;
0173 
0174     if (pipe != 0) {
0175         DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
0176         return -EINVAL;
0177     }
0178 
0179     status = via_read(dev_priv, VIA_REG_INTERRUPT);
0180     via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);
0181 
0182     via_write8(dev_priv, 0x83d4, 0x11);
0183     via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
0184 
0185     return 0;
0186 }
0187 
0188 void via_disable_vblank(struct drm_device *dev, unsigned int pipe)
0189 {
0190     drm_via_private_t *dev_priv = dev->dev_private;
0191     u32 status;
0192 
0193     status = via_read(dev_priv, VIA_REG_INTERRUPT);
0194     via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);
0195 
0196     via_write8(dev_priv, 0x83d4, 0x11);
0197     via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
0198 
0199     if (pipe != 0)
0200         DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
0201 }
0202 
0203 static int
0204 via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence,
0205             unsigned int *sequence)
0206 {
0207     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0208     unsigned int cur_irq_sequence;
0209     drm_via_irq_t *cur_irq;
0210     int ret = 0;
0211     maskarray_t *masks;
0212     int real_irq;
0213 
0214     DRM_DEBUG("\n");
0215 
0216     if (!dev_priv) {
0217         DRM_ERROR("called with no initialization\n");
0218         return -EINVAL;
0219     }
0220 
0221     if (irq >= drm_via_irq_num) {
0222         DRM_ERROR("Trying to wait on unknown irq %d\n", irq);
0223         return -EINVAL;
0224     }
0225 
0226     real_irq = dev_priv->irq_map[irq];
0227 
0228     if (real_irq < 0) {
0229         DRM_ERROR("Video IRQ %d not available on this hardware.\n",
0230               irq);
0231         return -EINVAL;
0232     }
0233 
0234     masks = dev_priv->irq_masks;
0235     cur_irq = dev_priv->via_irqs + real_irq;
0236 
0237     if (masks[real_irq][2] && !force_sequence) {
0238         VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
0239                 ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) ==
0240                  masks[irq][4]));
0241         cur_irq_sequence = atomic_read(&cur_irq->irq_received);
0242     } else {
0243         VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
0244                 (((cur_irq_sequence =
0245                    atomic_read(&cur_irq->irq_received)) -
0246                   *sequence) <= (1 << 23)));
0247     }
0248     *sequence = cur_irq_sequence;
0249     return ret;
0250 }
0251 
0252 
0253 /*
0254  * drm_dma.h hooks
0255  */
0256 
0257 void via_driver_irq_preinstall(struct drm_device *dev)
0258 {
0259     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0260     u32 status;
0261     drm_via_irq_t *cur_irq;
0262     int i;
0263 
0264     DRM_DEBUG("dev_priv: %p\n", dev_priv);
0265     if (dev_priv) {
0266         cur_irq = dev_priv->via_irqs;
0267 
0268         dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
0269         dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
0270 
0271         if (dev_priv->chipset == VIA_PRO_GROUP_A ||
0272             dev_priv->chipset == VIA_DX9_0) {
0273             dev_priv->irq_masks = via_pro_group_a_irqs;
0274             dev_priv->num_irqs = via_num_pro_group_a;
0275             dev_priv->irq_map = via_irqmap_pro_group_a;
0276         } else {
0277             dev_priv->irq_masks = via_unichrome_irqs;
0278             dev_priv->num_irqs = via_num_unichrome;
0279             dev_priv->irq_map = via_irqmap_unichrome;
0280         }
0281 
0282         for (i = 0; i < dev_priv->num_irqs; ++i) {
0283             atomic_set(&cur_irq->irq_received, 0);
0284             cur_irq->enable_mask = dev_priv->irq_masks[i][0];
0285             cur_irq->pending_mask = dev_priv->irq_masks[i][1];
0286             init_waitqueue_head(&cur_irq->irq_queue);
0287             dev_priv->irq_enable_mask |= cur_irq->enable_mask;
0288             dev_priv->irq_pending_mask |= cur_irq->pending_mask;
0289             cur_irq++;
0290 
0291             DRM_DEBUG("Initializing IRQ %d\n", i);
0292         }
0293 
0294         dev_priv->last_vblank_valid = 0;
0295 
0296         /* Clear VSync interrupt regs */
0297         status = via_read(dev_priv, VIA_REG_INTERRUPT);
0298         via_write(dev_priv, VIA_REG_INTERRUPT, status &
0299               ~(dev_priv->irq_enable_mask));
0300 
0301         /* Clear bits if they're already high */
0302         viadrv_acknowledge_irqs(dev_priv);
0303     }
0304 }
0305 
0306 int via_driver_irq_postinstall(struct drm_device *dev)
0307 {
0308     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0309     u32 status;
0310 
0311     DRM_DEBUG("fun: %s\n", __func__);
0312     if (!dev_priv)
0313         return -EINVAL;
0314 
0315     status = via_read(dev_priv, VIA_REG_INTERRUPT);
0316     via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
0317           | dev_priv->irq_enable_mask);
0318 
0319     /* Some magic, oh for some data sheets ! */
0320     via_write8(dev_priv, 0x83d4, 0x11);
0321     via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
0322 
0323     return 0;
0324 }
0325 
0326 void via_driver_irq_uninstall(struct drm_device *dev)
0327 {
0328     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0329     u32 status;
0330 
0331     DRM_DEBUG("\n");
0332     if (dev_priv) {
0333 
0334         /* Some more magic, oh for some data sheets ! */
0335 
0336         via_write8(dev_priv, 0x83d4, 0x11);
0337         via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
0338 
0339         status = via_read(dev_priv, VIA_REG_INTERRUPT);
0340         via_write(dev_priv, VIA_REG_INTERRUPT, status &
0341               ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
0342     }
0343 }
0344 
0345 int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
0346 {
0347     drm_via_irqwait_t *irqwait = data;
0348     struct timespec64 now;
0349     int ret = 0;
0350     drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
0351     drm_via_irq_t *cur_irq = dev_priv->via_irqs;
0352     int force_sequence;
0353 
0354     if (irqwait->request.irq >= dev_priv->num_irqs) {
0355         DRM_ERROR("Trying to wait on unknown irq %d\n",
0356               irqwait->request.irq);
0357         return -EINVAL;
0358     }
0359 
0360     cur_irq += irqwait->request.irq;
0361 
0362     switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
0363     case VIA_IRQ_RELATIVE:
0364         irqwait->request.sequence +=
0365             atomic_read(&cur_irq->irq_received);
0366         irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
0367         break;
0368     case VIA_IRQ_ABSOLUTE:
0369         break;
0370     default:
0371         return -EINVAL;
0372     }
0373 
0374     if (irqwait->request.type & VIA_IRQ_SIGNAL) {
0375         DRM_ERROR("Signals on Via IRQs not implemented yet.\n");
0376         return -EINVAL;
0377     }
0378 
0379     force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
0380 
0381     ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
0382                   &irqwait->request.sequence);
0383     ktime_get_ts64(&now);
0384     irqwait->reply.tval_sec = now.tv_sec;
0385     irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC;
0386 
0387     return ret;
0388 }