msm: ocmem: Add clock management support
Manage the OCMEM core and branch clocks and keep them
on only when required to minimize the power impact.
Change-Id: I33339b317c1ec76af27bae56c552cb50fef3da0c
Signed-off-by: Naveen Ramaraj <nramaraj@codeaurora.org>
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index b5754a7..82fe2f8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -296,6 +296,44 @@
}
#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
+/* Core Clock Operations */
+int ocmem_enable_core_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->core_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to enable core clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled core clock\n");
+ return 0;
+}
+
+void ocmem_disable_core_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->core_clk);
+ pr_debug("ocmem: Disabled core clock\n");
+}
+
+/* Branch Clock Operations */
+int ocmem_enable_iface_clock(void)
+{
+ int ret;
+ ret = clk_prepare_enable(ocmem_pdata->iface_clk);
+ if (ret) {
+ pr_err("ocmem: Failed to disable branch clock\n");
+ return ret;
+ }
+ pr_debug("ocmem: Enabled iface clock\n");
+ return 0;
+}
+
+void ocmem_disable_iface_clock(void)
+{
+ clk_disable_unprepare(ocmem_pdata->iface_clk);
+ pr_debug("ocmem: Disabled iface clock\n");
+}
+
static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -530,6 +568,7 @@
/* This will be programmed by TZ after TZ support is integrated */
static int ocmem_init_gfx_mpu(struct platform_device *pdev)
{
+ int rc;
struct device *dev = &pdev->dev;
void __iomem *ocmem_region_vbase = NULL;
@@ -538,13 +577,21 @@
if (!ocmem_region_vbase)
return -EBUSY;
+ rc = ocmem_enable_core_clock();
+
+ if (rc < 0)
+ return rc;
+
writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
+ ocmem_disable_core_clock();
return 0;
}
static int __devinit msm_ocmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct clk *ocmem_core_clk = NULL;
+ struct clk *ocmem_iface_clk = NULL;
if (!pdev->dev.of_node) {
dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -563,6 +610,29 @@
dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
+ ocmem_core_clk = devm_clk_get(dev, "core_clk");
+
+ if (IS_ERR(ocmem_core_clk)) {
+ dev_err(dev, "Unable to get the core clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ }
+
+ /* The core clock is synchronous with graphics */
+ if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
+ dev_err(dev, "Set rate failed on the core clock\n");
+ return -EBUSY;
+ }
+
+ ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
+
+ if (IS_ERR(ocmem_iface_clk)) {
+ dev_err(dev, "Unable to get the memory interface clock\n");
+ return PTR_ERR(ocmem_core_clk);
+ };
+
+ ocmem_pdata->core_clk = ocmem_core_clk;
+ ocmem_pdata->iface_clk = ocmem_iface_clk;
+
platform_set_drvdata(pdev, ocmem_pdata);
if (ocmem_core_init(pdev))