Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright 2008 Advanced Micro Devices, Inc.
  3.  * Copyright 2008 Red Hat Inc.
  4.  * Copyright 2009 Jerome Glisse.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in
  14.  * all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * OTHER DEALINGS IN THE SOFTWARE.
  23.  *
  24.  * Authors: Dave Airlie
  25.  *          Alex Deucher
  26.  *          Jerome Glisse
  27.  */
  28. #include <drm/drmP.h>
  29. #include "radeon.h"
  30. #include <drm/radeon_drm.h>
  31. #include "radeon_asic.h"
  32.  
  33. #include <linux/slab.h>
  34. #include <linux/pm_runtime.h>
  35.  
  36. #include "radeon_kfd.h"
  37.  
  38. #if defined(CONFIG_VGA_SWITCHEROO)
  39. bool radeon_has_atpx(void);
  40. #else
  41. static inline bool radeon_has_atpx(void) { return false; }
  42. #endif
  43.  
  44.  
  45. /*
  46.  * VBlank related functions.
  47.  */
  48. /**
  49.  * radeon_get_vblank_counter_kms - get frame count
  50.  *
  51.  * @dev: drm dev pointer
  52.  * @pipe: crtc to get the frame count from
  53.  *
  54.  * Gets the frame count on the requested crtc (all asics).
  55.  * Returns frame count on success, -EINVAL on failure.
  56.  */
  57. u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
  58. {
  59.         int vpos, hpos, stat;
  60.         u32 count;
  61.         struct radeon_device *rdev = dev->dev_private;
  62.  
  63.         if (pipe >= rdev->num_crtc) {
  64.                 DRM_ERROR("Invalid crtc %u\n", pipe);
  65.                 return -EINVAL;
  66.         }
  67.  
  68.         /* The hw increments its frame counter at start of vsync, not at start
  69.          * of vblank, as is required by DRM core vblank counter handling.
  70.          * Cook the hw count here to make it appear to the caller as if it
  71.          * incremented at start of vblank. We measure distance to start of
  72.          * vblank in vpos. vpos therefore will be >= 0 between start of vblank
  73.          * and start of vsync, so vpos >= 0 means to bump the hw frame counter
  74.          * result by 1 to give the proper appearance to caller.
  75.          */
  76.         if (rdev->mode_info.crtcs[pipe]) {
  77.                 /* Repeat readout if needed to provide stable result if
  78.                  * we cross start of vsync during the queries.
  79.                  */
  80.                 do {
  81.                         count = radeon_get_vblank_counter(rdev, pipe);
  82.                         /* Ask radeon_get_crtc_scanoutpos to return vpos as
  83.                          * distance to start of vblank, instead of regular
  84.                          * vertical scanout pos.
  85.                          */
  86.                         stat = radeon_get_crtc_scanoutpos(
  87.                                 dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
  88.                                 &vpos, &hpos, NULL, NULL,
  89.                                 &rdev->mode_info.crtcs[pipe]->base.hwmode);
  90.                 } while (count != radeon_get_vblank_counter(rdev, pipe));
  91.  
  92.                 if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
  93.                     (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
  94.                         DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
  95.                 }
  96.                 else {
  97.                         DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
  98.                                       pipe, vpos);
  99.  
  100.                         /* Bump counter if we are at >= leading edge of vblank,
  101.                          * but before vsync where vpos would turn negative and
  102.                          * the hw counter really increments.
  103.                          */
  104.                         if (vpos >= 0)
  105.                                 count++;
  106.                 }
  107.         }
  108.         else {
  109.             /* Fallback to use value as is. */
  110.             count = radeon_get_vblank_counter(rdev, pipe);
  111.             DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
  112.         }
  113.  
  114.         return count;
  115. }
  116.  
  117. /**
  118.  * radeon_enable_vblank_kms - enable vblank interrupt
  119.  *
  120.  * @dev: drm dev pointer
  121.  * @crtc: crtc to enable vblank interrupt for
  122.  *
  123.  * Enable the interrupt on the requested crtc (all asics).
  124.  * Returns 0 on success, -EINVAL on failure.
  125.  */
  126. int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
  127. {
  128.         struct radeon_device *rdev = dev->dev_private;
  129.         unsigned long irqflags;
  130.         int r;
  131.  
  132.         if (crtc < 0 || crtc >= rdev->num_crtc) {
  133.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  134.                 return -EINVAL;
  135.         }
  136.  
  137.         spin_lock_irqsave(&rdev->irq.lock, irqflags);
  138.         rdev->irq.crtc_vblank_int[crtc] = true;
  139.         r = radeon_irq_set(rdev);
  140.         spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
  141.         return r;
  142. }
  143.  
  144. /**
  145.  * radeon_disable_vblank_kms - disable vblank interrupt
  146.  *
  147.  * @dev: drm dev pointer
  148.  * @crtc: crtc to disable vblank interrupt for
  149.  *
  150.  * Disable the interrupt on the requested crtc (all asics).
  151.  */
  152. void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
  153. {
  154.         struct radeon_device *rdev = dev->dev_private;
  155.         unsigned long irqflags;
  156.  
  157.         if (crtc < 0 || crtc >= rdev->num_crtc) {
  158.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  159.                 return;
  160.         }
  161.  
  162.         spin_lock_irqsave(&rdev->irq.lock, irqflags);
  163.         rdev->irq.crtc_vblank_int[crtc] = false;
  164.         radeon_irq_set(rdev);
  165.         spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
  166. }
  167.  
  168. /**
  169.  * radeon_get_vblank_timestamp_kms - get vblank timestamp
  170.  *
  171.  * @dev: drm dev pointer
  172.  * @crtc: crtc to get the timestamp for
  173.  * @max_error: max error
  174.  * @vblank_time: time value
  175.  * @flags: flags passed to the driver
  176.  *
  177.  * Gets the timestamp on the requested crtc based on the
  178.  * scanout position.  (all asics).
  179.  * Returns postive status flags on success, negative error on failure.
  180.  */
  181. int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
  182.                                     int *max_error,
  183.                                     struct timeval *vblank_time,
  184.                                     unsigned flags)
  185. {
  186.         struct drm_crtc *drmcrtc;
  187.         struct radeon_device *rdev = dev->dev_private;
  188.  
  189.         if (crtc < 0 || crtc >= dev->num_crtcs) {
  190.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  191.                 return -EINVAL;
  192.         }
  193.  
  194.         /* Get associated drm_crtc: */
  195.         drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
  196.         if (!drmcrtc)
  197.                 return -EINVAL;
  198.  
  199.         /* Helper routine in DRM core does all the work: */
  200.         return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
  201.                                                      vblank_time, flags,
  202.                                                      &drmcrtc->hwmode);
  203. }
  204.  
  205.  
  206.