Subversion Repositories Kolibri OS

Rev

Rev 4293 | Rev 4560 | 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_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
  49.         ((count) % DRM_VBLANKTIME_RBSIZE)])
  50.  
  51. /* Retry timestamp calculation up to 3 times to satisfy
  52.  * drm_timestamp_precision before giving up.
  53.  */
  54. #define DRM_TIMESTAMP_MAXRETRIES 3
  55.  
  56. /* Threshold in nanoseconds for detection of redundant
  57.  * vblank irq in drm_handle_vblank(). 1 msec should be ok.
  58.  */
  59. #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
  60.  
  61.  
  62. irqreturn_t device_irq_handler(struct drm_device *dev)
  63. {
  64.  
  65. //    printf("video irq\n");
  66.  
  67. //    printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ;
  68.  
  69.     return dev->driver->irq_handler(0, dev);
  70. }
  71.  
  72. /**
  73.  * Install IRQ handler.
  74.  *
  75.  * \param dev DRM device.
  76.  *
  77.  * Initializes the IRQ related data. Installs the handler, calling the driver
  78.  * \c irq_preinstall() and \c irq_postinstall() functions
  79.  * before and after the installation.
  80.  */
  81. int drm_irq_install(struct drm_device *dev)
  82. {
  83.         int ret;
  84.     unsigned long sh_flags = 0;
  85.         char *irqname;
  86.  
  87.         if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
  88.                 return -EINVAL;
  89.  
  90.         if (drm_dev_to_irq(dev) == 0)
  91.                 return -EINVAL;
  92.  
  93.     mutex_lock(&dev->struct_mutex);
  94.  
  95.     /* Driver must have been initialized */
  96.     if (!dev->dev_private) {
  97.             mutex_unlock(&dev->struct_mutex);
  98.             return -EINVAL;
  99.     }
  100.  
  101.     if (dev->irq_enabled) {
  102.             mutex_unlock(&dev->struct_mutex);
  103.             return -EBUSY;
  104.     }
  105.     dev->irq_enabled = 1;
  106.     mutex_unlock(&dev->struct_mutex);
  107.  
  108.     DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev));
  109.  
  110.     /* Before installing handler */
  111.     if (dev->driver->irq_preinstall)
  112.             dev->driver->irq_preinstall(dev);
  113.  
  114.     ret = !AttachIntHandler(drm_dev_to_irq(dev), device_irq_handler, (u32)dev);
  115.  
  116.     /* After installing handler */
  117.     if (dev->driver->irq_postinstall)
  118.             ret = dev->driver->irq_postinstall(dev);
  119.  
  120.     if (ret < 0) {
  121.                 dev->irq_enabled = 0;
  122.         DRM_ERROR(__FUNCTION__);
  123.     }
  124.  
  125.     u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
  126.     cmd&= ~(1<<10);
  127.     PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
  128.  
  129.     return ret;
  130. }
  131. EXPORT_SYMBOL(drm_irq_install);
  132.  
  133.  
  134.  
  135.  
  136. u64 div64_u64(u64 dividend, u64 divisor)
  137. {
  138.         u32 high, d;
  139.  
  140.         high = divisor >> 32;
  141.         if (high) {
  142.                 unsigned int shift = fls(high);
  143.  
  144.                 d = divisor >> shift;
  145.                 dividend >>= shift;
  146.         } else
  147.                 d = divisor;
  148.  
  149.         return div_u64(dividend, d);
  150. }
  151.  
  152. /**
  153.  * drm_calc_timestamping_constants - Calculate and
  154.  * store various constants which are later needed by
  155.  * vblank and swap-completion timestamping, e.g, by
  156.  * drm_calc_vbltimestamp_from_scanoutpos().
  157.  * They are derived from crtc's true scanout timing,
  158.  * so they take things like panel scaling or other
  159.  * adjustments into account.
  160.  *
  161.  * @crtc drm_crtc whose timestamp constants should be updated.
  162.  *
  163.  */
  164. void drm_calc_timestamping_constants(struct drm_crtc *crtc)
  165. {
  166.         s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
  167.         u64 dotclock;
  168.  
  169.         /* Dot clock in Hz: */
  170.         dotclock = (u64) crtc->hwmode.clock * 1000;
  171.  
  172.         /* Fields of interlaced scanout modes are only halve a frame duration.
  173.          * Double the dotclock to get halve the frame-/line-/pixelduration.
  174.          */
  175.         if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
  176.                 dotclock *= 2;
  177.  
  178.         /* Valid dotclock? */
  179.         if (dotclock > 0) {
  180.                 int frame_size;
  181.                 /* Convert scanline length in pixels and video dot clock to
  182.                  * line duration, frame duration and pixel duration in
  183.                  * nanoseconds:
  184.                  */
  185.                 pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
  186.                 linedur_ns  = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
  187.                                               1000000000), dotclock);
  188.                 frame_size = crtc->hwmode.crtc_htotal *
  189.                                 crtc->hwmode.crtc_vtotal;
  190.                 framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000,
  191.                                               dotclock);
  192.         } else
  193.                 DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
  194.                           crtc->base.id);
  195.  
  196.         crtc->pixeldur_ns = pixeldur_ns;
  197.         crtc->linedur_ns  = linedur_ns;
  198.         crtc->framedur_ns = framedur_ns;
  199.  
  200.         DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
  201.                   crtc->base.id, crtc->hwmode.crtc_htotal,
  202.                   crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
  203.         DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
  204.                   crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
  205.                   (int) linedur_ns, (int) pixeldur_ns);
  206. }
  207. EXPORT_SYMBOL(drm_calc_timestamping_constants);
  208.  
  209. /**
  210.  * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
  211.  * drivers. Implements calculation of exact vblank timestamps from
  212.  * given drm_display_mode timings and current video scanout position
  213.  * of a crtc. This can be called from within get_vblank_timestamp()
  214.  * implementation of a kms driver to implement the actual timestamping.
  215.  *
  216.  * Should return timestamps conforming to the OML_sync_control OpenML
  217.  * extension specification. The timestamp corresponds to the end of
  218.  * the vblank interval, aka start of scanout of topmost-leftmost display
  219.  * pixel in the following video frame.
  220.  *
  221.  * Requires support for optional dev->driver->get_scanout_position()
  222.  * in kms driver, plus a bit of setup code to provide a drm_display_mode
  223.  * that corresponds to the true scanout timing.
  224.  *
  225.  * The current implementation only handles standard video modes. It
  226.  * returns as no operation if a doublescan or interlaced video mode is
  227.  * active. Higher level code is expected to handle this.
  228.  *
  229.  * @dev: DRM device.
  230.  * @crtc: Which crtc's vblank timestamp to retrieve.
  231.  * @max_error: Desired maximum allowable error in timestamps (nanosecs).
  232.  *             On return contains true maximum error of timestamp.
  233.  * @vblank_time: Pointer to struct timeval which should receive the timestamp.
  234.  * @flags: Flags to pass to driver:
  235.  *         0 = Default.
  236.  *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
  237.  * @refcrtc: drm_crtc* of crtc which defines scanout timing.
  238.  *
  239.  * Returns negative value on error, failure or if not supported in current
  240.  * video mode:
  241.  *
  242.  * -EINVAL   - Invalid crtc.
  243.  * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
  244.  * -ENOTSUPP - Function not supported in current display mode.
  245.  * -EIO      - Failed, e.g., due to failed scanout position query.
  246.  *
  247.  * Returns or'ed positive status flags on success:
  248.  *
  249.  * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
  250.  * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
  251.  *
  252.  */
  253. int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
  254.                                           int *max_error,
  255.                                           struct timeval *vblank_time,
  256.                                           unsigned flags,
  257.                                           struct drm_crtc *refcrtc)
  258. {
  259. //      ktime_t stime, etime, mono_time_offset;
  260.         struct timeval tv_etime;
  261.         struct drm_display_mode *mode;
  262.         int vbl_status, vtotal, vdisplay;
  263.         int vpos, hpos, i;
  264.         s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
  265.         bool invbl;
  266.  
  267.         if (crtc < 0 || crtc >= dev->num_crtcs) {
  268.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  269.                 return -EINVAL;
  270.         }
  271.  
  272.         /* Scanout position query not supported? Should not happen. */
  273.         if (!dev->driver->get_scanout_position) {
  274.                 DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
  275.                 return -EIO;
  276.         }
  277.  
  278.         mode = &refcrtc->hwmode;
  279.         vtotal = mode->crtc_vtotal;
  280.         vdisplay = mode->crtc_vdisplay;
  281.  
  282.         /* Durations of frames, lines, pixels in nanoseconds. */
  283.         framedur_ns = refcrtc->framedur_ns;
  284.         linedur_ns  = refcrtc->linedur_ns;
  285.         pixeldur_ns = refcrtc->pixeldur_ns;
  286.  
  287.         /* If mode timing undefined, just return as no-op:
  288.          * Happens during initial modesetting of a crtc.
  289.          */
  290.         if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
  291.                 DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
  292.                 return -EAGAIN;
  293.         }
  294.  
  295.         return -EIO;
  296. }
  297. EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
  298.  
  299.  
  300. /**
  301.  * drm_vblank_pre_modeset - account for vblanks across mode sets
  302.  * @dev: DRM device
  303.  * @crtc: CRTC in question
  304.  *
  305.  * Account for vblank events across mode setting events, which will likely
  306.  * reset the hardware frame counter.
  307.  */
  308. void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
  309. {
  310. #if 0
  311.     /* vblank is not initialized (IRQ not installed ?) */
  312.     if (!dev->num_crtcs)
  313.         return;
  314.     /*
  315.      * To avoid all the problems that might happen if interrupts
  316.      * were enabled/disabled around or between these calls, we just
  317.      * have the kernel take a reference on the CRTC (just once though
  318.      * to avoid corrupting the count if multiple, mismatch calls occur),
  319.      * so that interrupts remain enabled in the interim.
  320.      */
  321.     if (!dev->vblank_inmodeset[crtc]) {
  322.         dev->vblank_inmodeset[crtc] = 0x1;
  323.         if (drm_vblank_get(dev, crtc) == 0)
  324.             dev->vblank_inmodeset[crtc] |= 0x2;
  325.     }
  326. #endif
  327. }
  328. EXPORT_SYMBOL(drm_vblank_pre_modeset);
  329.  
  330. void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
  331. {
  332. #if 0
  333.     unsigned long irqflags;
  334.  
  335.         /* vblank is not initialized (IRQ not installed ?), or has been freed */
  336.         if (!dev->num_crtcs)
  337.                 return;
  338.  
  339.     if (dev->vblank_inmodeset[crtc]) {
  340.         spin_lock_irqsave(&dev->vbl_lock, irqflags);
  341.         dev->vblank_disable_allowed = 1;
  342.         spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  343.  
  344.         if (dev->vblank_inmodeset[crtc] & 0x2)
  345.             drm_vblank_put(dev, crtc);
  346.  
  347.         dev->vblank_inmodeset[crtc] = 0;
  348.     }
  349. #endif
  350. }
  351. EXPORT_SYMBOL(drm_vblank_post_modeset);
  352.