Subversion Repositories Kolibri OS

Rev

Rev 6938 | 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/vga_switcheroo.h>
  34. #include <linux/slab.h>
  35. #include <linux/pm_runtime.h>
  36.  
  37. #include "radeon_kfd.h"
  38.  
  39. #if defined(CONFIG_VGA_SWITCHEROO)
  40. bool radeon_has_atpx(void);
  41. #else
  42. static inline bool radeon_has_atpx(void) { return false; }
  43. #endif
  44.  
  45.  
  46. /*
  47.  * VBlank related functions.
  48.  */
  49. /**
  50.  * radeon_get_vblank_counter_kms - get frame count
  51.  *
  52.  * @dev: drm dev pointer
  53.  * @pipe: crtc to get the frame count from
  54.  *
  55.  * Gets the frame count on the requested crtc (all asics).
  56.  * Returns frame count on success, -EINVAL on failure.
  57.  */
  58. u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
  59. {
  60.         int vpos, hpos, stat;
  61.         u32 count;
  62.         struct radeon_device *rdev = dev->dev_private;
  63.  
  64.         if (pipe >= rdev->num_crtc) {
  65.                 DRM_ERROR("Invalid crtc %u\n", pipe);
  66.                 return -EINVAL;
  67.         }
  68.  
  69.         /* The hw increments its frame counter at start of vsync, not at start
  70.          * of vblank, as is required by DRM core vblank counter handling.
  71.          * Cook the hw count here to make it appear to the caller as if it
  72.          * incremented at start of vblank. We measure distance to start of
  73.          * vblank in vpos. vpos therefore will be >= 0 between start of vblank
  74.          * and start of vsync, so vpos >= 0 means to bump the hw frame counter
  75.          * result by 1 to give the proper appearance to caller.
  76.          */
  77.         if (rdev->mode_info.crtcs[pipe]) {
  78.                 /* Repeat readout if needed to provide stable result if
  79.                  * we cross start of vsync during the queries.
  80.                  */
  81.                 do {
  82.                         count = radeon_get_vblank_counter(rdev, pipe);
  83.                         /* Ask radeon_get_crtc_scanoutpos to return vpos as
  84.                          * distance to start of vblank, instead of regular
  85.                          * vertical scanout pos.
  86.                          */
  87.                         stat = radeon_get_crtc_scanoutpos(
  88.                                 dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
  89.                                 &vpos, &hpos, NULL, NULL,
  90.                                 &rdev->mode_info.crtcs[pipe]->base.hwmode);
  91.                 } while (count != radeon_get_vblank_counter(rdev, pipe));
  92.  
  93.                 if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
  94.                     (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
  95.                         DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
  96.                 }
  97.                 else {
  98.                         DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
  99.                                       pipe, vpos);
  100.  
  101.                         /* Bump counter if we are at >= leading edge of vblank,
  102.                          * but before vsync where vpos would turn negative and
  103.                          * the hw counter really increments.
  104.                          */
  105.                         if (vpos >= 0)
  106.                                 count++;
  107.                 }
  108.         }
  109.         else {
  110.             /* Fallback to use value as is. */
  111.             count = radeon_get_vblank_counter(rdev, pipe);
  112.             DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
  113.         }
  114.  
  115.         return count;
  116. }
  117.  
  118. /**
  119.  * radeon_enable_vblank_kms - enable vblank interrupt
  120.  *
  121.  * @dev: drm dev pointer
  122.  * @crtc: crtc to enable vblank interrupt for
  123.  *
  124.  * Enable the interrupt on the requested crtc (all asics).
  125.  * Returns 0 on success, -EINVAL on failure.
  126.  */
  127. int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
  128. {
  129.         struct radeon_device *rdev = dev->dev_private;
  130.         unsigned long irqflags;
  131.         int r;
  132.  
  133.         if (crtc < 0 || crtc >= rdev->num_crtc) {
  134.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  135.                 return -EINVAL;
  136.         }
  137.  
  138.         spin_lock_irqsave(&rdev->irq.lock, irqflags);
  139.         rdev->irq.crtc_vblank_int[crtc] = true;
  140.         r = radeon_irq_set(rdev);
  141.         spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
  142.         return r;
  143. }
  144.  
  145. /**
  146.  * radeon_disable_vblank_kms - disable vblank interrupt
  147.  *
  148.  * @dev: drm dev pointer
  149.  * @crtc: crtc to disable vblank interrupt for
  150.  *
  151.  * Disable the interrupt on the requested crtc (all asics).
  152.  */
  153. void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
  154. {
  155.         struct radeon_device *rdev = dev->dev_private;
  156.         unsigned long irqflags;
  157.  
  158.         if (crtc < 0 || crtc >= rdev->num_crtc) {
  159.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  160.                 return;
  161.         }
  162.  
  163.         spin_lock_irqsave(&rdev->irq.lock, irqflags);
  164.         rdev->irq.crtc_vblank_int[crtc] = false;
  165.         radeon_irq_set(rdev);
  166.         spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
  167. }
  168.  
  169. /**
  170.  * radeon_get_vblank_timestamp_kms - get vblank timestamp
  171.  *
  172.  * @dev: drm dev pointer
  173.  * @crtc: crtc to get the timestamp for
  174.  * @max_error: max error
  175.  * @vblank_time: time value
  176.  * @flags: flags passed to the driver
  177.  *
  178.  * Gets the timestamp on the requested crtc based on the
  179.  * scanout position.  (all asics).
  180.  * Returns postive status flags on success, negative error on failure.
  181.  */
  182. int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
  183.                                     int *max_error,
  184.                                     struct timeval *vblank_time,
  185.                                     unsigned flags)
  186. {
  187.         struct drm_crtc *drmcrtc;
  188.         struct radeon_device *rdev = dev->dev_private;
  189.  
  190.         if (crtc < 0 || crtc >= dev->num_crtcs) {
  191.                 DRM_ERROR("Invalid crtc %d\n", crtc);
  192.                 return -EINVAL;
  193.         }
  194.  
  195.         /* Get associated drm_crtc: */
  196.         drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
  197.         if (!drmcrtc)
  198.                 return -EINVAL;
  199.  
  200.         /* Helper routine in DRM core does all the work: */
  201.         return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
  202.                                                      vblank_time, flags,
  203.                                                      &drmcrtc->hwmode);
  204. }
  205.  
  206.  
  207.