blob: fdd28341976e36e812ee705cd2be49299558c8a7 [file] [log] [blame]
/**************************************************************************
* Copyright (c) 2012, Intel Corporation.
* All Rights Reserved.
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Authors:
* Hitesh K. Patel <hitesh.k.patel@intel.com>
*/
#include <linux/mutex.h>
#include <asm/intel-mid.h>
#include <asm/intel_scu_ipc.h>
#include <linux/pm_runtime.h>
#include "psb_drv.h"
#include "pwr_mgmt.h"
#define DISPLAY_RESUME_TO (HZ/4)
static struct delayed_work resume_work;
extern struct ospm_power_island island_list[9];
extern struct drm_device *gpDrmDevice;
int rtpm_suspend(struct device *dev)
{
struct drm_psb_private *dev_priv = gpDrmDevice->dev_private;
PSB_DEBUG_PM("%s\n", __func__);
rtpm_suspend_pci();
cancel_delayed_work(&resume_work);
pm_qos_update_request(&dev_priv->s0ix_qos, PM_QOS_DEFAULT_VALUE);
return 0;
}
int rtpm_resume(struct device *dev)
{
struct drm_psb_private *dev_priv = gpDrmDevice->dev_private;
PSB_DEBUG_PM("%s\n", __func__);
pm_qos_update_request(&dev_priv->s0ix_qos, CSTATE_EXIT_LATENCY_S0i1 - 1);
/* No OPs of GFX/VED/VEC/VSP/DISP */
rtpm_resume_pci();
return 0;
}
static void resume_work_task(struct work_struct *work)
{
/* w/a: force a display power transition after resume to unblock s0ix */
if (power_island_get(OSPM_DISPLAY_A))
power_island_put(OSPM_DISPLAY_A);
}
int rtpm_resume_end(struct device *dev)
{
schedule_delayed_work(&resume_work, DISPLAY_RESUME_TO);
return 0;
}
int rtpm_idle(struct device *dev)
{
int ref_count = 0;
int i;
PSB_DEBUG_PM("%s\n", __func__);
for (i = 0; i < ARRAY_SIZE(island_list); i++)
ref_count += atomic_read(&island_list[i].ref_count);
if (ref_count) {
PSB_DEBUG_PM("%s return busy\n", __func__);
return -EBUSY;
} else
return 0;
}
int rtpm_allow(struct drm_device *dev)
{
PSB_DEBUG_PM("%s\n", __func__);
pm_runtime_allow(&dev->pdev->dev);
return 0;
}
void rtpm_forbid(struct drm_device *dev)
{
PSB_DEBUG_PM("%s\n", __func__);
pm_runtime_forbid(&dev->pdev->dev);
return;
}
void rtpm_init(struct drm_device *dev)
{
rtpm_allow(dev);
INIT_DEFERRABLE_WORK(&resume_work, resume_work_task);
}
void rtpm_uninit(struct drm_device *dev)
{
pm_runtime_get_noresume(&dev->pdev->dev);
}