root/drivers/gpu/drm/gma500/power.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gma_power_init
  2. gma_power_uninit
  3. gma_suspend_display
  4. gma_resume_display
  5. gma_suspend_pci
  6. gma_resume_pci
  7. gma_power_suspend
  8. gma_power_resume
  9. gma_power_is_on
  10. gma_power_begin
  11. gma_power_end
  12. psb_runtime_suspend
  13. psb_runtime_resume
  14. psb_runtime_idle
  15. gma_power_thaw
  16. gma_power_freeze
  17. gma_power_restore

   1 /**************************************************************************
   2  * Copyright (c) 2009-2011, Intel Corporation.
   3  * All Rights Reserved.
   4  *
   5  * Permission is hereby granted, free of charge, to any person obtaining a
   6  * copy of this software and associated documentation files (the "Software"),
   7  * to deal in the Software without restriction, including without limitation
   8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   9  * and/or sell copies of the Software, and to permit persons to whom the
  10  * Software is furnished to do so, subject to the following conditions:
  11  *
  12  * The above copyright notice and this permission notice (including the next
  13  * paragraph) shall be included in all copies or substantial portions of the
  14  * 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22  * SOFTWARE.
  23  *
  24  * Authors:
  25  *    Benjamin Defnet <benjamin.r.defnet@intel.com>
  26  *    Rajesh Poornachandran <rajesh.poornachandran@intel.com>
  27  * Massively reworked
  28  *    Alan Cox <alan@linux.intel.com>
  29  */
  30 
  31 #include "power.h"
  32 #include "psb_drv.h"
  33 #include "psb_reg.h"
  34 #include "psb_intel_reg.h"
  35 #include <linux/mutex.h>
  36 #include <linux/pm_runtime.h>
  37 
  38 static struct mutex power_mutex;        /* Serialize power ops */
  39 static spinlock_t power_ctrl_lock;      /* Serialize power claim */
  40 
  41 /**
  42  *      gma_power_init          -       initialise power manager
  43  *      @dev: our device
  44  *
  45  *      Set up for power management tracking of our hardware.
  46  */
  47 void gma_power_init(struct drm_device *dev)
  48 {
  49         struct drm_psb_private *dev_priv = dev->dev_private;
  50 
  51         /* FIXME: Move APM/OSPM base into relevant device code */
  52         dev_priv->apm_base = dev_priv->apm_reg & 0xffff;
  53         dev_priv->ospm_base &= 0xffff;
  54 
  55         dev_priv->display_power = true; /* We start active */
  56         dev_priv->display_count = 0;    /* Currently no users */
  57         dev_priv->suspended = false;    /* And not suspended */
  58         spin_lock_init(&power_ctrl_lock);
  59         mutex_init(&power_mutex);
  60 
  61         if (dev_priv->ops->init_pm)
  62                 dev_priv->ops->init_pm(dev);
  63 }
  64 
  65 /**
  66  *      gma_power_uninit        -       end power manager
  67  *      @dev: device to end for
  68  *
  69  *      Undo the effects of gma_power_init
  70  */
  71 void gma_power_uninit(struct drm_device *dev)
  72 {
  73         pm_runtime_disable(&dev->pdev->dev);
  74         pm_runtime_set_suspended(&dev->pdev->dev);
  75 }
  76 
  77 /**
  78  *      gma_suspend_display     -       suspend the display logic
  79  *      @dev: our DRM device
  80  *
  81  *      Suspend the display logic of the graphics interface
  82  */
  83 static void gma_suspend_display(struct drm_device *dev)
  84 {
  85         struct drm_psb_private *dev_priv = dev->dev_private;
  86 
  87         if (dev_priv->suspended)
  88                 return;
  89         dev_priv->ops->save_regs(dev);
  90         dev_priv->ops->power_down(dev);
  91         dev_priv->display_power = false;
  92 }
  93 
  94 /**
  95  *      gma_resume_display      -       resume display side logic
  96  *
  97  *      Resume the display hardware restoring state and enabling
  98  *      as necessary.
  99  */
 100 static void gma_resume_display(struct pci_dev *pdev)
 101 {
 102         struct drm_device *dev = pci_get_drvdata(pdev);
 103         struct drm_psb_private *dev_priv = dev->dev_private;
 104 
 105         /* turn on the display power island */
 106         dev_priv->ops->power_up(dev);
 107         dev_priv->suspended = false;
 108         dev_priv->display_power = true;
 109 
 110         PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
 111         pci_write_config_word(pdev, PSB_GMCH_CTRL,
 112                         dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
 113 
 114         psb_gtt_restore(dev); /* Rebuild our GTT mappings */
 115         dev_priv->ops->restore_regs(dev);
 116 }
 117 
 118 /**
 119  *      gma_suspend_pci         -       suspend PCI side
 120  *      @pdev: PCI device
 121  *
 122  *      Perform the suspend processing on our PCI device state
 123  */
 124 static void gma_suspend_pci(struct pci_dev *pdev)
 125 {
 126         struct drm_device *dev = pci_get_drvdata(pdev);
 127         struct drm_psb_private *dev_priv = dev->dev_private;
 128         int bsm, vbt;
 129 
 130         if (dev_priv->suspended)
 131                 return;
 132 
 133         pci_save_state(pdev);
 134         pci_read_config_dword(pdev, 0x5C, &bsm);
 135         dev_priv->regs.saveBSM = bsm;
 136         pci_read_config_dword(pdev, 0xFC, &vbt);
 137         dev_priv->regs.saveVBT = vbt;
 138         pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
 139         pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
 140 
 141         pci_disable_device(pdev);
 142         pci_set_power_state(pdev, PCI_D3hot);
 143 
 144         dev_priv->suspended = true;
 145 }
 146 
 147 /**
 148  *      gma_resume_pci          -       resume helper
 149  *      @dev: our PCI device
 150  *
 151  *      Perform the resume processing on our PCI device state - rewrite
 152  *      register state and re-enable the PCI device
 153  */
 154 static bool gma_resume_pci(struct pci_dev *pdev)
 155 {
 156         struct drm_device *dev = pci_get_drvdata(pdev);
 157         struct drm_psb_private *dev_priv = dev->dev_private;
 158         int ret;
 159 
 160         if (!dev_priv->suspended)
 161                 return true;
 162 
 163         pci_set_power_state(pdev, PCI_D0);
 164         pci_restore_state(pdev);
 165         pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
 166         pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
 167         /* restoring MSI address and data in PCIx space */
 168         pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
 169         pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
 170         ret = pci_enable_device(pdev);
 171 
 172         if (ret != 0)
 173                 dev_err(&pdev->dev, "pci_enable failed: %d\n", ret);
 174         else
 175                 dev_priv->suspended = false;
 176         return !dev_priv->suspended;
 177 }
 178 
 179 /**
 180  *      gma_power_suspend               -       bus callback for suspend
 181  *      @pdev: our PCI device
 182  *      @state: suspend type
 183  *
 184  *      Called back by the PCI layer during a suspend of the system. We
 185  *      perform the necessary shut down steps and save enough state that
 186  *      we can undo this when resume is called.
 187  */
 188 int gma_power_suspend(struct device *_dev)
 189 {
 190         struct pci_dev *pdev = to_pci_dev(_dev);
 191         struct drm_device *dev = pci_get_drvdata(pdev);
 192         struct drm_psb_private *dev_priv = dev->dev_private;
 193 
 194         mutex_lock(&power_mutex);
 195         if (!dev_priv->suspended) {
 196                 if (dev_priv->display_count) {
 197                         mutex_unlock(&power_mutex);
 198                         dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
 199                         return -EBUSY;
 200                 }
 201                 psb_irq_uninstall(dev);
 202                 gma_suspend_display(dev);
 203                 gma_suspend_pci(pdev);
 204         }
 205         mutex_unlock(&power_mutex);
 206         return 0;
 207 }
 208 
 209 /**
 210  *      gma_power_resume                -       resume power
 211  *      @pdev: PCI device
 212  *
 213  *      Resume the PCI side of the graphics and then the displays
 214  */
 215 int gma_power_resume(struct device *_dev)
 216 {
 217         struct pci_dev *pdev = to_pci_dev(_dev);
 218         struct drm_device *dev = pci_get_drvdata(pdev);
 219 
 220         mutex_lock(&power_mutex);
 221         gma_resume_pci(pdev);
 222         gma_resume_display(pdev);
 223         psb_irq_preinstall(dev);
 224         psb_irq_postinstall(dev);
 225         mutex_unlock(&power_mutex);
 226         return 0;
 227 }
 228 
 229 /**
 230  *      gma_power_is_on         -       returne true if power is on
 231  *      @dev: our DRM device
 232  *
 233  *      Returns true if the display island power is on at this moment
 234  */
 235 bool gma_power_is_on(struct drm_device *dev)
 236 {
 237         struct drm_psb_private *dev_priv = dev->dev_private;
 238         return dev_priv->display_power;
 239 }
 240 
 241 /**
 242  *      gma_power_begin         -       begin requiring power
 243  *      @dev: our DRM device
 244  *      @force_on: true to force power on
 245  *
 246  *      Begin an action that requires the display power island is enabled.
 247  *      We refcount the islands.
 248  */
 249 bool gma_power_begin(struct drm_device *dev, bool force_on)
 250 {
 251         struct drm_psb_private *dev_priv = dev->dev_private;
 252         int ret;
 253         unsigned long flags;
 254 
 255         spin_lock_irqsave(&power_ctrl_lock, flags);
 256         /* Power already on ? */
 257         if (dev_priv->display_power) {
 258                 dev_priv->display_count++;
 259                 pm_runtime_get(&dev->pdev->dev);
 260                 spin_unlock_irqrestore(&power_ctrl_lock, flags);
 261                 return true;
 262         }
 263         if (force_on == false)
 264                 goto out_false;
 265 
 266         /* Ok power up needed */
 267         ret = gma_resume_pci(dev->pdev);
 268         if (ret == 0) {
 269                 psb_irq_preinstall(dev);
 270                 psb_irq_postinstall(dev);
 271                 pm_runtime_get(&dev->pdev->dev);
 272                 dev_priv->display_count++;
 273                 spin_unlock_irqrestore(&power_ctrl_lock, flags);
 274                 return true;
 275         }
 276 out_false:
 277         spin_unlock_irqrestore(&power_ctrl_lock, flags);
 278         return false;
 279 }
 280 
 281 /**
 282  *      gma_power_end           -       end use of power
 283  *      @dev: Our DRM device
 284  *
 285  *      Indicate that one of our gma_power_begin() requested periods when
 286  *      the diplay island power is needed has completed.
 287  */
 288 void gma_power_end(struct drm_device *dev)
 289 {
 290         struct drm_psb_private *dev_priv = dev->dev_private;
 291         unsigned long flags;
 292         spin_lock_irqsave(&power_ctrl_lock, flags);
 293         dev_priv->display_count--;
 294         WARN_ON(dev_priv->display_count < 0);
 295         spin_unlock_irqrestore(&power_ctrl_lock, flags);
 296         pm_runtime_put(&dev->pdev->dev);
 297 }
 298 
 299 int psb_runtime_suspend(struct device *dev)
 300 {
 301         return gma_power_suspend(dev);
 302 }
 303 
 304 int psb_runtime_resume(struct device *dev)
 305 {
 306         return gma_power_resume(dev);
 307 }
 308 
 309 int psb_runtime_idle(struct device *dev)
 310 {
 311         struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev));
 312         struct drm_psb_private *dev_priv = drmdev->dev_private;
 313         if (dev_priv->display_count)
 314                 return 0;
 315         else
 316                 return 1;
 317 }
 318 
 319 int gma_power_thaw(struct device *_dev)
 320 {
 321         return gma_power_resume(_dev);
 322 }
 323 
 324 int gma_power_freeze(struct device *_dev)
 325 {
 326         return gma_power_suspend(_dev);
 327 }
 328 
 329 int gma_power_restore(struct device *_dev)
 330 {
 331         return gma_power_resume(_dev);
 332 }

/* [<][>][^][v][top][bottom][index][help] */