Subversion Repositories Kolibri OS

Rev

Rev 4539 | Rev 5271 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**
  2.  * \file drm_irq.c
  3.  * IRQ support
  4.  *
  5.  * \author Rickard E. (Rik) Faith <faith@valinux.com>
  6.  * \author Gareth Hughes <gareth@valinux.com>
  7.  */
  8.  
  9. /*
  10.  * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
  11.  *
  12.  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  13.  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  14.  * All Rights Reserved.
  15.  *
  16.  * Permission is hereby granted, free of charge, to any person obtaining a
  17.  * copy of this software and associated documentation files (the "Software"),
  18.  * to deal in the Software without restriction, including without limitation
  19.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20.  * and/or sell copies of the Software, and to permit persons to whom the
  21.  * Software is furnished to do so, subject to the following conditions:
  22.  *
  23.  * The above copyright notice and this permission notice (including the next
  24.  * paragraph) shall be included in all copies or substantial portions of the
  25.  * Software.
  26.  *
  27.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  30.  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  31.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  32.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  33.  * OTHER DEALINGS IN THE SOFTWARE.
  34.  */
  35.  
  36. #include <drm/drmP.h>
  37. #include <asm/div64.h>
  38. //#include "drm_trace.h"
  39.  
  40. //#include <linux/interrupt.h>   /* For task queue support */
  41. #include <linux/slab.h>
  42.  
  43. //#include <linux/vgaarb.h>
  44. #include <linux/export.h>
  45.  
  46. /* Access macro for slots in vblank timestamp ringbuffer. */
  47. #define vblanktimestamp(dev, crtc, count) \
  48.         ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
  49.  
  50. /* Retry timestamp calculation up to 3 times to satisfy
  51.  * drm_timestamp_precision before giving up.
  52.  */
  53. #define DRM_TIMESTAMP_MAXRETRIES 3
  54.  
  55. /* Threshold in nanoseconds for detection of redundant
  56.  * vblank irq in drm_handle_vblank(). 1 msec should be ok.
  57.  */
  58. #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
  59.  
  60.  
  61. irqreturn_t device_irq_handler(struct drm_device *dev)
  62. {
  63.  
  64. //    printf("video irq\n");
  65.  
  66. //    printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ;
  67.  
  68.     return dev->driver->irq_handler(0, dev);
  69. }
  70.  
  71. /**
  72.  * Install IRQ handler.
  73.  *
  74.  * \param dev DRM device.
  75.  *
  76.  * Initializes the IRQ related data. Installs the handler, calling the driver
  77.  * \c irq_preinstall() and \c irq_postinstall() functions
  78.  * before and after the installation.
  79.  */
  80. int drm_irq_install(struct drm_device *dev)
  81. {
  82.         int ret;
  83.     unsigned long sh_flags = 0;
  84.         char *irqname;
  85.  
  86.         if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
  87.                 return -EINVAL;
  88.  
  89.         if (drm_dev_to_irq(dev) == 0)
  90.                 return -EINVAL;
  91.  
  92.     mutex_lock(&dev->struct_mutex);
  93.  
  94.     /* Driver must have been initialized */
  95.     if (!dev->dev_private) {
  96.             mutex_unlock(&dev->struct_mutex);
  97.             return -EINVAL;
  98.     }
  99.  
  100.     if (dev->irq_enabled) {
  101.             mutex_unlock(&dev->struct_mutex);
  102.             return -EBUSY;
  103.     }
  104.         dev->irq_enabled = true;
  105.     mutex_unlock(&dev->struct_mutex);
  106.  
  107.     DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
  108.  
  109.     /* Before installing handler */
  110.     if (dev->driver->irq_preinstall)
  111.             dev->driver->irq_preinstall(dev);
  112.  
  113.     ret = !AttachIntHandler(drm_dev_to_irq(dev), device_irq_handler, (u32)dev);
  114.  
  115.     /* After installing handler */
  116.     if (dev->driver->irq_postinstall)
  117.             ret = dev->driver->irq_postinstall(dev);
  118.  
  119.     if (ret < 0) {
  120.                 dev->irq_enabled = 0;
  121.         DRM_ERROR(__FUNCTION__);
  122.     }
  123.  
  124.     u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
  125.     cmd&= ~(1<<10);
  126.     PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
  127.  
  128.     return ret;
  129. }
  130. EXPORT_SYMBOL(drm_irq_install);
  131.  
  132.  
  133.  
  134.  
  135. u64 div64_u64(u64 dividend, u64 divisor)
  136. {
  137.         u32 high, d;
  138.  
  139.         high = divisor >> 32;
  140.         if (high) {
  141.                 unsigned int shift = fls(high);
  142.  
  143.                 d = divisor >> shift;
  144.                 dividend >>= shift;
  145.         } else
  146.                 d = divisor;
  147.  
  148.         return div_u64(dividend, d);
  149. }
  150.  
  151. /**
  152.  * drm_calc_timestamping_constants - Calculate vblank timestamp constants
  153.  *
  154.  * @crtc drm_crtc whose timestamp constants should be updated.
  155.  * @mode display mode containing the scanout timings
  156.  *
  157.  * Calculate and store various constants which are later
  158.  * needed by vblank and swap-completion timestamping, e.g,
  159.  * by drm_calc_vbltimestamp_from_scanoutpos(). They are
  160.  * derived from crtc's true scanout timing, so they take
  161.  * things like panel scaling or other adjustments into account.
  162.  */
  163. void drm_calc_timestamping_constants(struct drm_crtc *crtc,
  164.                                      const struct drm_display_mode *mode)
  165. {
  166.         int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
  167.         int dotclock = mode->crtc_clock;
  168.  
  169.         /* Valid dotclock? */
  170.         if (dotclock > 0) {
  171.                 int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
  172.  
  173.                 /*
  174.                  * Convert scanline length in pixels and video
  175.                  * dot clock to line duration, frame duration
  176.                  * and pixel duration in nanoseconds:
  177.          */
  178.                 pixeldur_ns = 1000000 / dotclock;
  179.                 linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
  180.                 framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
  181.  
  182.                 /*
  183.                  * Fields of interlaced scanout modes are only half a frame duration.
  184.                  */
  185.                 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  186.                         framedur_ns /= 2;
  187.         } else
  188.                 DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
  189.                           crtc->base.id);
  190.  
  191.         crtc->pixeldur_ns = pixeldur_ns;
  192.         crtc->linedur_ns  = linedur_ns;
  193.         crtc->framedur_ns = framedur_ns;
  194.  
  195.         DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
  196.                   crtc->base.id, mode->crtc_htotal,
  197.                   mode->crtc_vtotal, mode->crtc_vdisplay);
  198.         DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
  199.                   crtc->base.id, dotclock, framedur_ns,
  200.                   linedur_ns, pixeldur_ns);
  201. }
  202. EXPORT_SYMBOL(drm_calc_timestamping_constants);
  203.  
  204. /**
  205.  * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
  206.  * drivers. Implements calculation of exact vblank timestamps from
  207.  * given drm_display_mode timings and current video scanout position
  208.  * of a crtc. This can be called from within get_vblank_timestamp()
  209.  * implementation of a kms driver to implement the actual timestamping.
  210.  *
  211.  * Should return timestamps conforming to the OML_sync_control OpenML
  212.  * extension specification. The timestamp corresponds to the end of
  213.  * the vblank interval, aka start of scanout of topmost-leftmost display
  214.  * pixel in the following video frame.
  215.  *
  216.  * Requires support for optional dev->driver->get_scanout_position()
  217.  * in kms driver, plus a bit of setup code to provide a drm_display_mode
  218.  * that corresponds to the true scanout timing.
  219.  *
  220.  * The current implementation only handles standard video modes. It
  221.  * returns as no operation if a doublescan or interlaced video mode is
  222.  * active. Higher level code is expected to handle this.
  223.  *
  224.  * @dev: DRM device.
  225.  * @crtc: Which crtc's vblank timestamp to retrieve.
  226.  * @max_error: Desired maximum allowable error in timestamps (nanosecs).
  227.  *             On return contains true maximum error of timestamp.
  228.  * @vblank_time: Pointer to struct timeval which should receive the timestamp.
  229.  * @flags: Flags to pass to driver:
  230.  *         0 = Default.
  231.  *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
  232.  * @refcrtc: drm_crtc* of crtc which defines scanout timing.
  233.  * @mode: mode which defines the scanout timings
  234.  *
  235.  * Returns negative value on error, failure or if not supported in current
  236.  * video mode:
  237.  *
  238.  * -EINVAL   - Invalid crtc.
  239.  * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
  240.  * -ENOTSUPP - Function not supported in current display mode.
  241.  * -EIO      - Failed, e.g., due to failed scanout position query.
  242.  *
  243.  * Returns or'ed positive status flags on success:
  244.  *
  245.  * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
  246.  * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
  247.  *
  248.  */
  249. int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
  250.                                           int *max_error,
  251.                                           struct timeval *vblank_time,
  252.                                           unsigned flags,
  253.                                           const struct drm_crtc *refcrtc,
  254.                                           const struct drm_display_mode *mode)
  255. {
  256.         struct timeval tv_etime;
  257.         int vbl_status;
  258.         int vpos, hpos, i;
  259.         int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
  260.         bool invbl;
  261.  
  262.         if (crtc < 0 || crtc >= dev->num_crtcs) {
  263.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  264.                 return -EINVAL;
  265.         }
  266.  
  267.         /* Scanout position query not supported? Should not happen. */
  268.         if (!dev->driver->get_scanout_position) {
  269.                 DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
  270.                 return -EIO;
  271.         }
  272.  
  273.         /* Durations of frames, lines, pixels in nanoseconds. */
  274.         framedur_ns = refcrtc->framedur_ns;
  275.         linedur_ns  = refcrtc->linedur_ns;
  276.         pixeldur_ns = refcrtc->pixeldur_ns;
  277.  
  278.         /* If mode timing undefined, just return as no-op:
  279.          * Happens during initial modesetting of a crtc.
  280.          */
  281.         if (framedur_ns == 0) {
  282.                 DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
  283.                 return -EAGAIN;
  284.         }
  285.  
  286.         return -EIO;
  287. }
  288. EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
  289.  
  290.  
  291. /**
  292.  * drm_vblank_pre_modeset - account for vblanks across mode sets
  293.  * @dev: DRM device
  294.  * @crtc: CRTC in question
  295.  *
  296.  * Account for vblank events across mode setting events, which will likely
  297.  * reset the hardware frame counter.
  298.  */
  299. void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
  300. {
  301. #if 0
  302.     /* vblank is not initialized (IRQ not installed ?) */
  303.     if (!dev->num_crtcs)
  304.         return;
  305.     /*
  306.      * To avoid all the problems that might happen if interrupts
  307.      * were enabled/disabled around or between these calls, we just
  308.      * have the kernel take a reference on the CRTC (just once though
  309.      * to avoid corrupting the count if multiple, mismatch calls occur),
  310.      * so that interrupts remain enabled in the interim.
  311.      */
  312.         if (!dev->vblank[crtc].inmodeset) {
  313.                 dev->vblank[crtc].inmodeset = 0x1;
  314.         if (drm_vblank_get(dev, crtc) == 0)
  315.                         dev->vblank[crtc].inmodeset |= 0x2;
  316.     }
  317. #endif
  318. }
  319. EXPORT_SYMBOL(drm_vblank_pre_modeset);
  320.  
  321. void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
  322. {
  323. #if 0
  324.     unsigned long irqflags;
  325.  
  326.         /* vblank is not initialized (IRQ not installed ?), or has been freed */
  327.         if (!dev->num_crtcs)
  328.                 return;
  329.  
  330.         if (dev->vblank[crtc].inmodeset) {
  331.         spin_lock_irqsave(&dev->vbl_lock, irqflags);
  332.                 dev->vblank_disable_allowed = true;
  333.         spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  334.  
  335.                 if (dev->vblank[crtc].inmodeset & 0x2)
  336.             drm_vblank_put(dev, crtc);
  337.  
  338.                 dev->vblank[crtc].inmodeset = 0;
  339.     }
  340. #endif
  341. }
  342. EXPORT_SYMBOL(drm_vblank_post_modeset);
  343.