[PATCH] drm/komeda: Adds system power management support

From: Lowry Li (Arm Technology China)
Date: Fri Jun 21 2019 - 03:57:37 EST


From: "Lowry Li (Arm Technology China)" <Lowry.Li@xxxxxxx>

Adds system power management support in KMS kernel driver.

Depends on:
- https://patchwork.freedesktop.org/series/61650/
- https://patchwork.freedesktop.org/series/60083/
- https://patchwork.freedesktop.org/series/61647/

Changes since v1:
Since we have unified mclk/pclk/pipeline->aclk to one mclk, which will
be turned on/off when crtc atomic enable/disable, removed runtime power
management.
Adds to disable the aclk when register access finished.

Changes since v2:
Removes run time get/put related flow.

Signed-off-by: Lowry Li (Arm Technology China) <lowry.li@xxxxxxx>
---
drivers/gpu/drm/arm/display/komeda/komeda_crtc.c | 1 -
drivers/gpu/drm/arm/display/komeda/komeda_dev.c | 63 +++++++++++++++++++++---
drivers/gpu/drm/arm/display/komeda/komeda_dev.h | 2 +
drivers/gpu/drm/arm/display/komeda/komeda_drv.c | 35 +++++++++++--
4 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
index cafb445..d14e7f3 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -5,7 +5,6 @@
*
*/
#include <linux/clk.h>
-#include <linux/pm_runtime.h>
#include <linux/spinlock.h>

#include <drm/drm_atomic.h>
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
index e1aa58e..c9837dc 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -209,7 +209,7 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
product->product_id,
MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
err = -ENODEV;
- goto err_cleanup;
+ goto disable_clk;
}

DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
@@ -222,19 +222,19 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
err = mdev->funcs->enum_resources(mdev);
if (err) {
DRM_ERROR("enumerate display resource failed.\n");
- goto err_cleanup;
+ goto disable_clk;
}

err = komeda_parse_dt(dev, mdev);
if (err) {
DRM_ERROR("parse device tree failed.\n");
- goto err_cleanup;
+ goto disable_clk;
}

err = komeda_assemble_pipelines(mdev);
if (err) {
DRM_ERROR("assemble display pipelines failed.\n");
- goto err_cleanup;
+ goto disable_clk;
}

dev->dma_parms = &mdev->dma_parms;
@@ -247,11 +247,13 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
if (mdev->iommu && mdev->funcs->connect_iommu) {
err = mdev->funcs->connect_iommu(mdev);
if (err) {
- mdev->iommu = NULL;
- goto err_cleanup;
+ DRM_ERROR("connect iommu failed.\n");
+ goto disable_clk;
}
}

+ clk_disable_unprepare(mdev->aclk);
+
err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
if (err) {
DRM_ERROR("create sysfs group failed.\n");
@@ -264,6 +266,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev)

return mdev;

+disable_clk:
+ clk_disable_unprepare(mdev->aclk);
err_cleanup:
komeda_dev_destroy(mdev);
return ERR_PTR(err);
@@ -281,6 +285,9 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
debugfs_remove_recursive(mdev->debugfs_root);
#endif

+ if (mdev->aclk)
+ clk_prepare_enable(mdev->aclk);
+
if (mdev->iommu && mdev->funcs->disconnect_iommu)
mdev->funcs->disconnect_iommu(mdev);
mdev->iommu = NULL;
@@ -308,3 +315,47 @@ void komeda_dev_destroy(struct komeda_dev *mdev)

devm_kfree(dev, mdev);
}
+
+int komeda_dev_resume(struct komeda_dev *mdev)
+{
+ int ret = 0;
+
+ clk_prepare_enable(mdev->aclk);
+
+ if (mdev->iommu && mdev->funcs->connect_iommu) {
+ ret = mdev->funcs->connect_iommu(mdev);
+ if (ret < 0) {
+ DRM_ERROR("connect iommu failed.\n");
+ goto disable_clk;
+ }
+ }
+
+ ret = mdev->funcs->enable_irq(mdev);
+
+disable_clk:
+ clk_disable_unprepare(mdev->aclk);
+
+ return ret;
+}
+
+int komeda_dev_suspend(struct komeda_dev *mdev)
+{
+ int ret = 0;
+
+ clk_prepare_enable(mdev->aclk);
+
+ if (mdev->iommu && mdev->funcs->disconnect_iommu) {
+ ret = mdev->funcs->disconnect_iommu(mdev);
+ if (ret < 0) {
+ DRM_ERROR("disconnect iommu failed.\n");
+ goto disable_clk;
+ }
+ }
+
+ ret = mdev->funcs->disable_irq(mdev);
+
+disable_clk:
+ clk_disable_unprepare(mdev->aclk);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
index d1c86b6..096f9f7 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -207,4 +207,6 @@ struct komeda_dev {

struct komeda_dev *dev_to_mdev(struct device *dev);

+int komeda_dev_resume(struct komeda_dev *mdev);
+int komeda_dev_suspend(struct komeda_dev *mdev);
#endif /*_KOMEDA_DEV_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
index cfa5068..52b2a94 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -32,6 +32,7 @@ static void komeda_unbind(struct device *dev)
return;

komeda_kms_detach(mdrv->kms);
+
komeda_dev_destroy(mdrv->mdev);

dev_set_drvdata(dev, NULL);
@@ -52,6 +53,7 @@ static int komeda_bind(struct device *dev)
err = PTR_ERR(mdrv->mdev);
goto free_mdrv;
}
+ dev_set_drvdata(dev, mdrv);

mdrv->kms = komeda_kms_attach(mdrv->mdev);
if (IS_ERR(mdrv->kms)) {
@@ -59,8 +61,6 @@ static int komeda_bind(struct device *dev)
goto destroy_mdev;
}

- dev_set_drvdata(dev, mdrv);
-
return 0;

destroy_mdev:
@@ -134,13 +134,42 @@ static int komeda_platform_remove(struct platform_device *pdev)

MODULE_DEVICE_TABLE(of, komeda_of_match);

+static int __maybe_unused komeda_pm_suspend(struct device *dev)
+{
+ struct komeda_drv *mdrv = dev_get_drvdata(dev);
+ struct drm_device *drm = &mdrv->kms->base;
+ int res;
+
+ dev_info(dev, "%s\n", __func__);
+ res = drm_mode_config_helper_suspend(drm);
+
+ komeda_dev_suspend(mdrv->mdev);
+
+ return res;
+}
+
+static int __maybe_unused komeda_pm_resume(struct device *dev)
+{
+ struct komeda_drv *mdrv = dev_get_drvdata(dev);
+ struct drm_device *drm = &mdrv->kms->base;
+
+ dev_info(dev, "%s\n", __func__);
+ komeda_dev_resume(mdrv->mdev);
+
+ return drm_mode_config_helper_resume(drm);
+}
+
+static const struct dev_pm_ops komeda_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume)
+};
+
static struct platform_driver komeda_platform_driver = {
.probe = komeda_platform_probe,
.remove = komeda_platform_remove,
.driver = {
.name = "komeda",
.of_match_table = komeda_of_match,
- .pm = NULL,
+ .pm = &komeda_pm_ops,
},
};

--
1.9.1