Skip to content

Commit

Permalink
drm/exynos: add runtime pm feature for fimd
Browse files Browse the repository at this point in the history
This adds runtime PM feature for fimd. The runtime PM functions control
clocks for fimd and prevent to access the register of fimd for vblank
when clock is turned off by suspend of runtime PM.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
  • Loading branch information
Joonyoung Shim authored and Inki Dae committed Dec 21, 2011
1 parent ec05da9 commit cb91f6a
Showing 1 changed file with 77 additions and 1 deletion.
78 changes: 77 additions & 1 deletion drivers/gpu/drm/exynos/exynos_drm_fimd.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>

#include <drm/exynos_drm.h>
#include <plat/regs-fb-v4.h>
Expand Down Expand Up @@ -85,6 +86,7 @@ struct fimd_context {
unsigned long irq_flags;
u32 vidcon0;
u32 vidcon1;
bool suspended;

struct fb_videomode *timing;
};
Expand Down Expand Up @@ -137,7 +139,19 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
{
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);

/* TODO */
switch (mode) {
case DRM_MODE_DPMS_ON:
pm_runtime_get_sync(subdrv_dev);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
pm_runtime_put_sync(subdrv_dev);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
break;
}
}

static void fimd_apply(struct device *subdrv_dev)
Expand Down Expand Up @@ -210,6 +224,9 @@ static int fimd_enable_vblank(struct device *dev)

DRM_DEBUG_KMS("%s\n", __FILE__);

if (ctx->suspended)
return -EPERM;

if (!test_and_set_bit(0, &ctx->irq_flags)) {
val = readl(ctx->regs + VIDINTCON0);

Expand All @@ -234,6 +251,9 @@ static void fimd_disable_vblank(struct device *dev)

DRM_DEBUG_KMS("%s\n", __FILE__);

if (ctx->suspended)
return;

if (test_and_clear_bit(0, &ctx->irq_flags)) {
val = readl(ctx->regs + VIDINTCON0);

Expand Down Expand Up @@ -760,6 +780,10 @@ static int __devinit fimd_probe(struct platform_device *pdev)
goto err_req_irq;
}

pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);

for (win = 0; win < WINDOWS_NR; win++)
fimd_clear_win(ctx, win);

Expand Down Expand Up @@ -812,14 +836,25 @@ static int __devinit fimd_probe(struct platform_device *pdev)

static int __devexit fimd_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fimd_context *ctx = platform_get_drvdata(pdev);

DRM_DEBUG_KMS("%s\n", __FILE__);

exynos_drm_subdrv_unregister(&ctx->subdrv);

if (ctx->suspended)
goto out;

clk_disable(ctx->lcd_clk);
clk_disable(ctx->bus_clk);

pm_runtime_set_suspended(dev);
pm_runtime_put_sync(dev);

out:
pm_runtime_disable(dev);

clk_put(ctx->lcd_clk);
clk_put(ctx->bus_clk);

Expand All @@ -833,12 +868,53 @@ static int __devexit fimd_remove(struct platform_device *pdev)
return 0;
}

#ifdef CONFIG_PM_RUNTIME
static int fimd_runtime_suspend(struct device *dev)
{
struct fimd_context *ctx = get_fimd_context(dev);

DRM_DEBUG_KMS("%s\n", __FILE__);

clk_disable(ctx->lcd_clk);
clk_disable(ctx->bus_clk);

ctx->suspended = true;
return 0;
}

static int fimd_runtime_resume(struct device *dev)
{
struct fimd_context *ctx = get_fimd_context(dev);
int ret;

DRM_DEBUG_KMS("%s\n", __FILE__);

ret = clk_enable(ctx->bus_clk);
if (ret < 0)
return ret;

ret = clk_enable(ctx->lcd_clk);
if (ret < 0) {
clk_disable(ctx->bus_clk);
return ret;
}

ctx->suspended = false;
return 0;
}
#endif

static const struct dev_pm_ops fimd_pm_ops = {
SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
};

static struct platform_driver fimd_driver = {
.probe = fimd_probe,
.remove = __devexit_p(fimd_remove),
.driver = {
.name = "exynos4-fb",
.owner = THIS_MODULE,
.pm = &fimd_pm_ops,
},
};

Expand Down

0 comments on commit cb91f6a

Please sign in to comment.