Home | History | Annotate | Line # | Download | only in via
via_irq.c revision 1.1.1.4
      1 /*	$NetBSD: via_irq.c,v 1.1.1.4 2021/12/18 20:15:54 riastradh Exp $	*/
      2 
      3 /* via_irq.c
      4  *
      5  * Copyright 2004 BEAM Ltd.
      6  * Copyright 2002 Tungsten Graphics, Inc.
      7  * Copyright 2005 Thomas Hellstrom.
      8  * All Rights Reserved.
      9  *
     10  * Permission is hereby granted, free of charge, to any person obtaining a
     11  * copy of this software and associated documentation files (the "Software"),
     12  * to deal in the Software without restriction, including without limitation
     13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     14  * and/or sell copies of the Software, and to permit persons to whom the
     15  * Software is furnished to do so, subject to the following conditions:
     16  *
     17  * The above copyright notice and this permission notice (including the next
     18  * paragraph) shall be included in all copies or substantial portions of the
     19  * Software.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     24  * BEAM LTD, TUNGSTEN GRAPHICS  AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     25  * DAMAGES OR
     26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     28  * DEALINGS IN THE SOFTWARE.
     29  *
     30  * Authors:
     31  *    Terry Barnaby <terry1 (at) beam.ltd.uk>
     32  *    Keith Whitwell <keith (at) tungstengraphics.com>
     33  *    Thomas Hellstrom <unichrome (at) shipmail.org>
     34  *
     35  * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
     36  * interrupt, as well as an infrastructure to handle other interrupts of the chip.
     37  * The refresh rate is also calculated for video playback sync purposes.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: via_irq.c,v 1.1.1.4 2021/12/18 20:15:54 riastradh Exp $");
     42 
     43 #include <drm/drm_device.h>
     44 #include <drm/drm_vblank.h>
     45 #include <drm/via_drm.h>
     46 
     47 #include "via_drv.h"
     48 
     49 #define VIA_REG_INTERRUPT       0x200
     50 
     51 /* VIA_REG_INTERRUPT */
     52 #define VIA_IRQ_GLOBAL	  (1 << 31)
     53 #define VIA_IRQ_VBLANK_ENABLE   (1 << 19)
     54 #define VIA_IRQ_VBLANK_PENDING  (1 << 3)
     55 #define VIA_IRQ_HQV0_ENABLE     (1 << 11)
     56 #define VIA_IRQ_HQV1_ENABLE     (1 << 25)
     57 #define VIA_IRQ_HQV0_PENDING    (1 << 9)
     58 #define VIA_IRQ_HQV1_PENDING    (1 << 10)
     59 #define VIA_IRQ_DMA0_DD_ENABLE  (1 << 20)
     60 #define VIA_IRQ_DMA0_TD_ENABLE  (1 << 21)
     61 #define VIA_IRQ_DMA1_DD_ENABLE  (1 << 22)
     62 #define VIA_IRQ_DMA1_TD_ENABLE  (1 << 23)
     63 #define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
     64 #define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
     65 #define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
     66 #define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
     67 
     68 
     69 /*
     70  * Device-specific IRQs go here. This type might need to be extended with
     71  * the register if there are multiple IRQ control registers.
     72  * Currently we activate the HQV interrupts of  Unichrome Pro group A.
     73  */
     74 
     75 static maskarray_t via_pro_group_a_irqs[] = {
     76 	{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
     77 	 0x00000000 },
     78 	{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
     79 	 0x00000000 },
     80 	{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
     81 	 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
     82 	{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
     83 	 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
     84 };
     85 static int via_num_pro_group_a = ARRAY_SIZE(via_pro_group_a_irqs);
     86 static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
     87 
     88 static maskarray_t via_unichrome_irqs[] = {
     89 	{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
     90 	 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
     91 	{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
     92 	 VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
     93 };
     94 static int via_num_unichrome = ARRAY_SIZE(via_unichrome_irqs);
     95 static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
     96 
     97 
     98 u32 via_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
     99 {
    100 	drm_via_private_t *dev_priv = dev->dev_private;
    101 
    102 	if (pipe != 0)
    103 		return 0;
    104 
    105 	return atomic_read(&dev_priv->vbl_received);
    106 }
    107 
    108 irqreturn_t via_driver_irq_handler(int irq, void *arg)
    109 {
    110 	struct drm_device *dev = (struct drm_device *) arg;
    111 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    112 	u32 status;
    113 	int handled = 0;
    114 	ktime_t cur_vblank;
    115 	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
    116 	int i;
    117 
    118 	status = via_read(dev_priv, VIA_REG_INTERRUPT);
    119 	if (status & VIA_IRQ_VBLANK_PENDING) {
    120 		atomic_inc(&dev_priv->vbl_received);
    121 		if (!(atomic_read(&dev_priv->vbl_received) & 0x0F)) {
    122 			cur_vblank = ktime_get();
    123 			if (dev_priv->last_vblank_valid) {
    124 				dev_priv->nsec_per_vblank =
    125 					ktime_sub(cur_vblank,
    126 						dev_priv->last_vblank) >> 4;
    127 			}
    128 			dev_priv->last_vblank = cur_vblank;
    129 			dev_priv->last_vblank_valid = 1;
    130 		}
    131 		if (!(atomic_read(&dev_priv->vbl_received) & 0xFF)) {
    132 			DRM_DEBUG("nsec per vblank is: %llu\n",
    133 				  ktime_to_ns(dev_priv->nsec_per_vblank));
    134 		}
    135 		drm_handle_vblank(dev, 0);
    136 		handled = 1;
    137 	}
    138 
    139 	for (i = 0; i < dev_priv->num_irqs; ++i) {
    140 		if (status & cur_irq->pending_mask) {
    141 			atomic_inc(&cur_irq->irq_received);
    142 			wake_up(&cur_irq->irq_queue);
    143 			handled = 1;
    144 			if (dev_priv->irq_map[drm_via_irq_dma0_td] == i)
    145 				via_dmablit_handler(dev, 0, 1);
    146 			else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i)
    147 				via_dmablit_handler(dev, 1, 1);
    148 		}
    149 		cur_irq++;
    150 	}
    151 
    152 	/* Acknowledge interrupts */
    153 	via_write(dev_priv, VIA_REG_INTERRUPT, status);
    154 
    155 
    156 	if (handled)
    157 		return IRQ_HANDLED;
    158 	else
    159 		return IRQ_NONE;
    160 }
    161 
    162 static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv)
    163 {
    164 	u32 status;
    165 
    166 	if (dev_priv) {
    167 		/* Acknowledge interrupts */
    168 		status = via_read(dev_priv, VIA_REG_INTERRUPT);
    169 		via_write(dev_priv, VIA_REG_INTERRUPT, status |
    170 			  dev_priv->irq_pending_mask);
    171 	}
    172 }
    173 
    174 int via_enable_vblank(struct drm_device *dev, unsigned int pipe)
    175 {
    176 	drm_via_private_t *dev_priv = dev->dev_private;
    177 	u32 status;
    178 
    179 	if (pipe != 0) {
    180 		DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
    181 		return -EINVAL;
    182 	}
    183 
    184 	status = via_read(dev_priv, VIA_REG_INTERRUPT);
    185 	via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_VBLANK_ENABLE);
    186 
    187 	via_write8(dev_priv, 0x83d4, 0x11);
    188 	via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
    189 
    190 	return 0;
    191 }
    192 
    193 void via_disable_vblank(struct drm_device *dev, unsigned int pipe)
    194 {
    195 	drm_via_private_t *dev_priv = dev->dev_private;
    196 	u32 status;
    197 
    198 	status = via_read(dev_priv, VIA_REG_INTERRUPT);
    199 	via_write(dev_priv, VIA_REG_INTERRUPT, status & ~VIA_IRQ_VBLANK_ENABLE);
    200 
    201 	via_write8(dev_priv, 0x83d4, 0x11);
    202 	via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
    203 
    204 	if (pipe != 0)
    205 		DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
    206 }
    207 
    208 static int
    209 via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence,
    210 		    unsigned int *sequence)
    211 {
    212 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    213 	unsigned int cur_irq_sequence;
    214 	drm_via_irq_t *cur_irq;
    215 	int ret = 0;
    216 	maskarray_t *masks;
    217 	int real_irq;
    218 
    219 	DRM_DEBUG("\n");
    220 
    221 	if (!dev_priv) {
    222 		DRM_ERROR("called with no initialization\n");
    223 		return -EINVAL;
    224 	}
    225 
    226 	if (irq >= drm_via_irq_num) {
    227 		DRM_ERROR("Trying to wait on unknown irq %d\n", irq);
    228 		return -EINVAL;
    229 	}
    230 
    231 	real_irq = dev_priv->irq_map[irq];
    232 
    233 	if (real_irq < 0) {
    234 		DRM_ERROR("Video IRQ %d not available on this hardware.\n",
    235 			  irq);
    236 		return -EINVAL;
    237 	}
    238 
    239 	masks = dev_priv->irq_masks;
    240 	cur_irq = dev_priv->via_irqs + real_irq;
    241 
    242 	if (masks[real_irq][2] && !force_sequence) {
    243 		VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
    244 			    ((via_read(dev_priv, masks[irq][2]) & masks[irq][3]) ==
    245 			     masks[irq][4]));
    246 		cur_irq_sequence = atomic_read(&cur_irq->irq_received);
    247 	} else {
    248 		VIA_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
    249 			    (((cur_irq_sequence =
    250 			       atomic_read(&cur_irq->irq_received)) -
    251 			      *sequence) <= (1 << 23)));
    252 	}
    253 	*sequence = cur_irq_sequence;
    254 	return ret;
    255 }
    256 
    257 
    258 /*
    259  * drm_dma.h hooks
    260  */
    261 
    262 void via_driver_irq_preinstall(struct drm_device *dev)
    263 {
    264 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    265 	u32 status;
    266 	drm_via_irq_t *cur_irq;
    267 	int i;
    268 
    269 	DRM_DEBUG("dev_priv: %p\n", dev_priv);
    270 	if (dev_priv) {
    271 		cur_irq = dev_priv->via_irqs;
    272 
    273 		dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
    274 		dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
    275 
    276 		if (dev_priv->chipset == VIA_PRO_GROUP_A ||
    277 		    dev_priv->chipset == VIA_DX9_0) {
    278 			dev_priv->irq_masks = via_pro_group_a_irqs;
    279 			dev_priv->num_irqs = via_num_pro_group_a;
    280 			dev_priv->irq_map = via_irqmap_pro_group_a;
    281 		} else {
    282 			dev_priv->irq_masks = via_unichrome_irqs;
    283 			dev_priv->num_irqs = via_num_unichrome;
    284 			dev_priv->irq_map = via_irqmap_unichrome;
    285 		}
    286 
    287 		for (i = 0; i < dev_priv->num_irqs; ++i) {
    288 			atomic_set(&cur_irq->irq_received, 0);
    289 			cur_irq->enable_mask = dev_priv->irq_masks[i][0];
    290 			cur_irq->pending_mask = dev_priv->irq_masks[i][1];
    291 			init_waitqueue_head(&cur_irq->irq_queue);
    292 			dev_priv->irq_enable_mask |= cur_irq->enable_mask;
    293 			dev_priv->irq_pending_mask |= cur_irq->pending_mask;
    294 			cur_irq++;
    295 
    296 			DRM_DEBUG("Initializing IRQ %d\n", i);
    297 		}
    298 
    299 		dev_priv->last_vblank_valid = 0;
    300 
    301 		/* Clear VSync interrupt regs */
    302 		status = via_read(dev_priv, VIA_REG_INTERRUPT);
    303 		via_write(dev_priv, VIA_REG_INTERRUPT, status &
    304 			  ~(dev_priv->irq_enable_mask));
    305 
    306 		/* Clear bits if they're already high */
    307 		viadrv_acknowledge_irqs(dev_priv);
    308 	}
    309 }
    310 
    311 int via_driver_irq_postinstall(struct drm_device *dev)
    312 {
    313 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    314 	u32 status;
    315 
    316 	DRM_DEBUG("via_driver_irq_postinstall\n");
    317 	if (!dev_priv)
    318 		return -EINVAL;
    319 
    320 	status = via_read(dev_priv, VIA_REG_INTERRUPT);
    321 	via_write(dev_priv, VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
    322 		  | dev_priv->irq_enable_mask);
    323 
    324 	/* Some magic, oh for some data sheets ! */
    325 	via_write8(dev_priv, 0x83d4, 0x11);
    326 	via_write8_mask(dev_priv, 0x83d5, 0x30, 0x30);
    327 
    328 	return 0;
    329 }
    330 
    331 void via_driver_irq_uninstall(struct drm_device *dev)
    332 {
    333 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    334 	u32 status;
    335 
    336 	DRM_DEBUG("\n");
    337 	if (dev_priv) {
    338 
    339 		/* Some more magic, oh for some data sheets ! */
    340 
    341 		via_write8(dev_priv, 0x83d4, 0x11);
    342 		via_write8_mask(dev_priv, 0x83d5, 0x30, 0);
    343 
    344 		status = via_read(dev_priv, VIA_REG_INTERRUPT);
    345 		via_write(dev_priv, VIA_REG_INTERRUPT, status &
    346 			  ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
    347 	}
    348 }
    349 
    350 int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
    351 {
    352 	drm_via_irqwait_t *irqwait = data;
    353 	struct timespec64 now;
    354 	int ret = 0;
    355 	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    356 	drm_via_irq_t *cur_irq = dev_priv->via_irqs;
    357 	int force_sequence;
    358 
    359 	if (irqwait->request.irq >= dev_priv->num_irqs) {
    360 		DRM_ERROR("Trying to wait on unknown irq %d\n",
    361 			  irqwait->request.irq);
    362 		return -EINVAL;
    363 	}
    364 
    365 	cur_irq += irqwait->request.irq;
    366 
    367 	switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
    368 	case VIA_IRQ_RELATIVE:
    369 		irqwait->request.sequence +=
    370 			atomic_read(&cur_irq->irq_received);
    371 		irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
    372 	case VIA_IRQ_ABSOLUTE:
    373 		break;
    374 	default:
    375 		return -EINVAL;
    376 	}
    377 
    378 	if (irqwait->request.type & VIA_IRQ_SIGNAL) {
    379 		DRM_ERROR("Signals on Via IRQs not implemented yet.\n");
    380 		return -EINVAL;
    381 	}
    382 
    383 	force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
    384 
    385 	ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
    386 				  &irqwait->request.sequence);
    387 	ktime_get_ts64(&now);
    388 	irqwait->reply.tval_sec = now.tv_sec;
    389 	irqwait->reply.tval_usec = now.tv_nsec / NSEC_PER_USEC;
    390 
    391 	return ret;
    392 }
    393