Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * drm_irq.c IRQ and vblank support
  3.  *
  4.  * \author Rickard E. (Rik) Faith <faith@valinux.com>
  5.  * \author Gareth Hughes <gareth@valinux.com>
  6.  */
  7.  
  8. /*
  9.  * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
  10.  *
  11.  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
  12.  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
  13.  * All Rights Reserved.
  14.  *
  15.  * Permission is hereby granted, free of charge, to any person obtaining a
  16.  * copy of this software and associated documentation files (the "Software"),
  17.  * to deal in the Software without restriction, including without limitation
  18.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19.  * and/or sell copies of the Software, and to permit persons to whom the
  20.  * Software is furnished to do so, subject to the following conditions:
  21.  *
  22.  * The above copyright notice and this permission notice (including the next
  23.  * paragraph) shall be included in all copies or substantial portions of the
  24.  * Software.
  25.  *
  26.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  29.  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  30.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  31.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  32.  * OTHER DEALINGS IN THE SOFTWARE.
  33.  */
  34.  
  35. #include <drm/drmP.h>
  36. #include <asm/div64.h>
  37. //#include "drm_trace.h"
  38.  
  39. //#include <linux/interrupt.h>   /* For task queue support */
  40. #include <linux/slab.h>
  41.  
  42. //#include <linux/vgaarb.h>
  43. #include <linux/export.h>
  44.  
  45. /* Access macro for slots in vblank timestamp ringbuffer. */
  46. #define vblanktimestamp(dev, crtc, count) \
  47.         ((dev)->vblank[crtc].time[(count) % DRM_VBLANKTIME_RBSIZE])
  48.  
  49. /* Retry timestamp calculation up to 3 times to satisfy
  50.  * drm_timestamp_precision before giving up.
  51.  */
  52. #define DRM_TIMESTAMP_MAXRETRIES 3
  53.  
  54. /* Threshold in nanoseconds for detection of redundant
  55.  * vblank irq in drm_handle_vblank(). 1 msec should be ok.
  56.  */
  57. #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
  58.  
  59. /*
  60.  * Clear vblank timestamp buffer for a crtc.
  61.  */
  62.  
  63.  
  64. #if 0
  65. /**
  66.  * drm_vblank_init - initialize vblank support
  67.  * @dev: drm_device
  68.  * @num_crtcs: number of crtcs supported by @dev
  69.  *
  70.  * This function initializes vblank support for @num_crtcs display pipelines.
  71.  *
  72.  * Returns:
  73.  * Zero on success or a negative error code on failure.
  74.  */
  75. int drm_vblank_init(struct drm_device *dev, int num_crtcs)
  76. {
  77.         int i, ret = -ENOMEM;
  78.  
  79.         spin_lock_init(&dev->vbl_lock);
  80.         spin_lock_init(&dev->vblank_time_lock);
  81.  
  82.         dev->num_crtcs = num_crtcs;
  83.  
  84.         dev->vblank = kcalloc(num_crtcs, sizeof(*dev->vblank), GFP_KERNEL);
  85.         if (!dev->vblank)
  86.                 goto err;
  87.  
  88.         for (i = 0; i < num_crtcs; i++) {
  89.                 dev->vblank[i].dev = dev;
  90.                 dev->vblank[i].crtc = i;
  91.                 init_waitqueue_head(&dev->vblank[i].queue);
  92.                 setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn,
  93.                             (unsigned long)&dev->vblank[i]);
  94.         }
  95.  
  96.         DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n");
  97.  
  98.         /* Driver specific high-precision vblank timestamping supported? */
  99.         if (dev->driver->get_vblank_timestamp)
  100.                 DRM_INFO("Driver supports precise vblank timestamp query.\n");
  101.         else
  102.                 DRM_INFO("No driver support for vblank timestamp query.\n");
  103.  
  104.         dev->vblank_disable_allowed = false;
  105.  
  106.         return 0;
  107.  
  108. err:
  109.         drm_vblank_cleanup(dev);
  110.         return ret;
  111. }
  112. EXPORT_SYMBOL(drm_vblank_init);
  113.  
  114. #endif
  115.  
  116. irqreturn_t device_irq_handler(struct drm_device *dev)
  117. {
  118.  
  119. //    printf("video irq\n");
  120.  
  121. //    printf("device %p driver %p handler %p\n", dev, dev->driver, dev->driver->irq_handler) ;
  122.  
  123.     return dev->driver->irq_handler(0, dev);
  124. }
  125.  
  126. /**
  127.  * drm_irq_install - install IRQ handler
  128.  * @dev: DRM device
  129.  * @irq: IRQ number to install the handler for
  130.  *
  131.  * Initializes the IRQ related data. Installs the handler, calling the driver
  132.  * irq_preinstall() and irq_postinstall() functions before and after the
  133.  * installation.
  134.  *
  135.  * This is the simplified helper interface provided for drivers with no special
  136.  * needs. Drivers which need to install interrupt handlers for multiple
  137.  * interrupts must instead set drm_device->irq_enabled to signal the DRM core
  138.  * that vblank interrupts are available.
  139.  *
  140.  * Returns:
  141.  * Zero on success or a negative error code on failure.
  142.  */
  143. int drm_irq_install(struct drm_device *dev, int irq)
  144. {
  145.         int ret;
  146.     unsigned long sh_flags = 0;
  147.  
  148.         if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
  149.                 return -EINVAL;
  150.  
  151.         if (irq == 0)
  152.                 return -EINVAL;
  153.  
  154.     /* Driver must have been initialized */
  155.         if (!dev->dev_private)
  156.             return -EINVAL;
  157.  
  158.         if (dev->irq_enabled)
  159.             return -EBUSY;
  160.         dev->irq_enabled = true;
  161.  
  162.         DRM_DEBUG("irq=%d\n", irq);
  163.  
  164.     /* Before installing handler */
  165.     if (dev->driver->irq_preinstall)
  166.             dev->driver->irq_preinstall(dev);
  167.  
  168.     ret = !AttachIntHandler(irq, device_irq_handler, (u32)dev);
  169.  
  170.     /* After installing handler */
  171.     if (dev->driver->irq_postinstall)
  172.             ret = dev->driver->irq_postinstall(dev);
  173.  
  174.     if (ret < 0) {
  175.                 dev->irq_enabled = false;
  176.         DRM_ERROR(__FUNCTION__);
  177.         } else {
  178.                 dev->irq = irq;
  179.     }
  180.  
  181.     u16_t cmd = PciRead16(dev->pdev->busnr, dev->pdev->devfn, 4);
  182.     cmd&= ~(1<<10);
  183.     PciWrite16(dev->pdev->busnr, dev->pdev->devfn, 4, cmd);
  184.  
  185.     return ret;
  186. }
  187. EXPORT_SYMBOL(drm_irq_install);
  188.  
  189.  
  190.  
  191.  
  192. u64 div64_u64(u64 dividend, u64 divisor)
  193. {
  194.         u32 high, d;
  195.  
  196.         high = divisor >> 32;
  197.         if (high) {
  198.                 unsigned int shift = fls(high);
  199.  
  200.                 d = divisor >> shift;
  201.                 dividend >>= shift;
  202.         } else
  203.                 d = divisor;
  204.  
  205.         return div_u64(dividend, d);
  206. }
  207.  
  208. /**
  209.  * drm_calc_timestamping_constants - calculate vblank timestamp constants
  210.  * @crtc: drm_crtc whose timestamp constants should be updated.
  211.  * @mode: display mode containing the scanout timings
  212.  *
  213.  * Calculate and store various constants which are later
  214.  * needed by vblank and swap-completion timestamping, e.g,
  215.  * by drm_calc_vbltimestamp_from_scanoutpos(). They are
  216.  * derived from CRTC's true scanout timing, so they take
  217.  * things like panel scaling or other adjustments into account.
  218.  */
  219. void drm_calc_timestamping_constants(struct drm_crtc *crtc,
  220.                                      const struct drm_display_mode *mode)
  221. {
  222.         int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
  223.         int dotclock = mode->crtc_clock;
  224.  
  225.         /* Valid dotclock? */
  226.         if (dotclock > 0) {
  227.                 int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
  228.  
  229.                 /*
  230.                  * Convert scanline length in pixels and video
  231.                  * dot clock to line duration, frame duration
  232.                  * and pixel duration in nanoseconds:
  233.          */
  234.                 pixeldur_ns = 1000000 / dotclock;
  235.                 linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
  236.                 framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
  237.  
  238.                 /*
  239.                  * Fields of interlaced scanout modes are only half a frame duration.
  240.                  */
  241.                 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  242.                         framedur_ns /= 2;
  243.         } else
  244.                 DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
  245.                           crtc->base.id);
  246.  
  247.         crtc->pixeldur_ns = pixeldur_ns;
  248.         crtc->linedur_ns  = linedur_ns;
  249.         crtc->framedur_ns = framedur_ns;
  250.  
  251.         DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
  252.                   crtc->base.id, mode->crtc_htotal,
  253.                   mode->crtc_vtotal, mode->crtc_vdisplay);
  254.         DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
  255.                   crtc->base.id, dotclock, framedur_ns,
  256.                   linedur_ns, pixeldur_ns);
  257. }
  258. EXPORT_SYMBOL(drm_calc_timestamping_constants);
  259.  
  260. /**
  261.  * drm_calc_vbltimestamp_from_scanoutpos - precise vblank timestamp helper
  262.  * @dev: DRM device
  263.  * @crtc: Which CRTC's vblank timestamp to retrieve
  264.  * @max_error: Desired maximum allowable error in timestamps (nanosecs)
  265.  *             On return contains true maximum error of timestamp
  266.  * @vblank_time: Pointer to struct timeval which should receive the timestamp
  267.  * @flags: Flags to pass to driver:
  268.  *         0 = Default,
  269.  *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl IRQ handler
  270.  * @refcrtc: CRTC which defines scanout timing
  271.  * @mode: mode which defines the scanout timings
  272.  *
  273.  * Implements calculation of exact vblank timestamps from given drm_display_mode
  274.  * timings and current video scanout position of a CRTC. This can be called from
  275.  * within get_vblank_timestamp() implementation of a kms driver to implement the
  276.  * actual timestamping.
  277.  *
  278.  * Should return timestamps conforming to the OML_sync_control OpenML
  279.  * extension specification. The timestamp corresponds to the end of
  280.  * the vblank interval, aka start of scanout of topmost-leftmost display
  281.  * pixel in the following video frame.
  282.  *
  283.  * Requires support for optional dev->driver->get_scanout_position()
  284.  * in kms driver, plus a bit of setup code to provide a drm_display_mode
  285.  * that corresponds to the true scanout timing.
  286.  *
  287.  * The current implementation only handles standard video modes. It
  288.  * returns as no operation if a doublescan or interlaced video mode is
  289.  * active. Higher level code is expected to handle this.
  290.  *
  291.  * Returns:
  292.  * Negative value on error, failure or if not supported in current
  293.  * video mode:
  294.  *
  295.  * -EINVAL   - Invalid CRTC.
  296.  * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
  297.  * -ENOTSUPP - Function not supported in current display mode.
  298.  * -EIO      - Failed, e.g., due to failed scanout position query.
  299.  *
  300.  * Returns or'ed positive status flags on success:
  301.  *
  302.  * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
  303.  * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval.
  304.  *
  305.  */
  306. int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
  307.                                           int *max_error,
  308.                                           struct timeval *vblank_time,
  309.                                           unsigned flags,
  310.                                           const struct drm_crtc *refcrtc,
  311.                                           const struct drm_display_mode *mode)
  312. {
  313.         struct timeval tv_etime;
  314.         int vbl_status;
  315.         int vpos, hpos, i;
  316.         int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
  317.         bool invbl;
  318.  
  319.         if (crtc < 0 || crtc >= dev->num_crtcs) {
  320.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  321.                 return -EINVAL;
  322.         }
  323.  
  324.         /* Scanout position query not supported? Should not happen. */
  325.         if (!dev->driver->get_scanout_position) {
  326.                 DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
  327.                 return -EIO;
  328.         }
  329.  
  330.         /* Durations of frames, lines, pixels in nanoseconds. */
  331.         framedur_ns = refcrtc->framedur_ns;
  332.         linedur_ns  = refcrtc->linedur_ns;
  333.         pixeldur_ns = refcrtc->pixeldur_ns;
  334.  
  335.         /* If mode timing undefined, just return as no-op:
  336.          * Happens during initial modesetting of a crtc.
  337.          */
  338.         if (framedur_ns == 0) {
  339.                 DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
  340.                 return -EAGAIN;
  341.         }
  342.  
  343.         return -EIO;
  344. }
  345. EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
  346.  
  347. /**
  348.  * drm_vblank_off - disable vblank events on a CRTC
  349.  * @dev: DRM device
  350.  * @crtc: CRTC in question
  351.  *
  352.  * Drivers can use this function to shut down the vblank interrupt handling when
  353.  * disabling a crtc. This function ensures that the latest vblank frame count is
  354.  * stored so that drm_vblank_on() can restore it again.
  355.  *
  356.  * Drivers must use this function when the hardware vblank counter can get
  357.  * reset, e.g. when suspending.
  358.  *
  359.  * This is the legacy version of drm_crtc_vblank_off().
  360.  */
  361. void drm_vblank_off(struct drm_device *dev, int crtc)
  362. {
  363.         struct drm_pending_vblank_event *e, *t;
  364.         struct timeval now;
  365.         unsigned long irqflags;
  366.         unsigned int seq;
  367.  
  368.  
  369. }
  370. EXPORT_SYMBOL(drm_vblank_off);
  371.  
  372. /**
  373.  * drm_crtc_vblank_off - disable vblank events on a CRTC
  374.  * @crtc: CRTC in question
  375.  *
  376.  * Drivers can use this function to shut down the vblank interrupt handling when
  377.  * disabling a crtc. This function ensures that the latest vblank frame count is
  378.  * stored so that drm_vblank_on can restore it again.
  379.  *
  380.  * Drivers must use this function when the hardware vblank counter can get
  381.  * reset, e.g. when suspending.
  382.  *
  383.  * This is the native kms version of drm_vblank_off().
  384.  */
  385. void drm_crtc_vblank_off(struct drm_crtc *crtc)
  386. {
  387.         drm_vblank_off(crtc->dev, drm_crtc_index(crtc));
  388. }
  389. EXPORT_SYMBOL(drm_crtc_vblank_off);
  390.  
  391. /**
  392.  * drm_vblank_on - enable vblank events on a CRTC
  393.  * @dev: DRM device
  394.  * @crtc: CRTC in question
  395.  *
  396.  * This functions restores the vblank interrupt state captured with
  397.  * drm_vblank_off() again. Note that calls to drm_vblank_on() and
  398.  * drm_vblank_off() can be unbalanced and so can also be unconditionaly called
  399.  * in driver load code to reflect the current hardware state of the crtc.
  400.  *
  401.  * This is the legacy version of drm_crtc_vblank_on().
  402.  */
  403. void drm_vblank_on(struct drm_device *dev, int crtc)
  404. {
  405.         unsigned long irqflags;
  406.  
  407. }
  408. EXPORT_SYMBOL(drm_vblank_on);
  409.  
  410. /**
  411.  * drm_crtc_vblank_on - enable vblank events on a CRTC
  412.  * @crtc: CRTC in question
  413.  *
  414.  * This functions restores the vblank interrupt state captured with
  415.  * drm_vblank_off() again. Note that calls to drm_vblank_on() and
  416.  * drm_vblank_off() can be unbalanced and so can also be unconditionaly called
  417.  * in driver load code to reflect the current hardware state of the crtc.
  418.  *
  419.  * This is the native kms version of drm_vblank_on().
  420.  */
  421. void drm_crtc_vblank_on(struct drm_crtc *crtc)
  422. {
  423.         drm_vblank_on(crtc->dev, drm_crtc_index(crtc));
  424. }
  425. EXPORT_SYMBOL(drm_crtc_vblank_on);
  426.  
  427. /**
  428.  * drm_vblank_pre_modeset - account for vblanks across mode sets
  429.  * @dev: DRM device
  430.  * @crtc: CRTC in question
  431.  *
  432.  * Account for vblank events across mode setting events, which will likely
  433.  * reset the hardware frame counter.
  434.  *
  435.  * This is done by grabbing a temporary vblank reference to ensure that the
  436.  * vblank interrupt keeps running across the modeset sequence. With this the
  437.  * software-side vblank frame counting will ensure that there are no jumps or
  438.  * discontinuities.
  439.  *
  440.  * Unfortunately this approach is racy and also doesn't work when the vblank
  441.  * interrupt stops running, e.g. across system suspend resume. It is therefore
  442.  * highly recommended that drivers use the newer drm_vblank_off() and
  443.  * drm_vblank_on() instead. drm_vblank_pre_modeset() only works correctly when
  444.  * using "cooked" software vblank frame counters and not relying on any hardware
  445.  * counters.
  446.  *
  447.  * Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc
  448.  * again.
  449.  */
  450. void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
  451. {
  452. #if 0
  453.     /* vblank is not initialized (IRQ not installed ?) */
  454.     if (!dev->num_crtcs)
  455.         return;
  456.     /*
  457.      * To avoid all the problems that might happen if interrupts
  458.      * were enabled/disabled around or between these calls, we just
  459.      * have the kernel take a reference on the CRTC (just once though
  460.      * to avoid corrupting the count if multiple, mismatch calls occur),
  461.      * so that interrupts remain enabled in the interim.
  462.      */
  463.         if (!dev->vblank[crtc].inmodeset) {
  464.                 dev->vblank[crtc].inmodeset = 0x1;
  465.         if (drm_vblank_get(dev, crtc) == 0)
  466.                         dev->vblank[crtc].inmodeset |= 0x2;
  467.     }
  468. #endif
  469. }
  470. EXPORT_SYMBOL(drm_vblank_pre_modeset);
  471.  
  472. /**
  473.  * drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes
  474.  * @dev: DRM device
  475.  * @crtc: CRTC in question
  476.  *
  477.  * This function again drops the temporary vblank reference acquired in
  478.  * drm_vblank_pre_modeset.
  479.  */
  480. void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
  481. {
  482. #if 0
  483.     unsigned long irqflags;
  484.  
  485.         /* vblank is not initialized (IRQ not installed ?), or has been freed */
  486.         if (!dev->num_crtcs)
  487.                 return;
  488.  
  489.         if (dev->vblank[crtc].inmodeset) {
  490.         spin_lock_irqsave(&dev->vbl_lock, irqflags);
  491.                 dev->vblank_disable_allowed = true;
  492.         spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
  493.  
  494.                 if (dev->vblank[crtc].inmodeset & 0x2)
  495.             drm_vblank_put(dev, crtc);
  496.  
  497.                 dev->vblank[crtc].inmodeset = 0;
  498.     }
  499. #endif
  500. }
  501. EXPORT_SYMBOL(drm_vblank_post_modeset);
  502.