msm: vidc: Set no memory retention for video clocks

Currently, certain memories are set to retain their contents
even after clocks are off. Here, we set the no memory retention
flags for the associated clocks, to save power.

CRs-Fixed: 1044381
Change-Id: I87c34fece6cb352ecef3aaeb8a02c1196fa8bcc3
Signed-off-by: Chinmay Sawarkar <chinmays@codeaurora.org>
This commit is contained in:
Chinmay Sawarkar 2016-08-01 18:30:45 -07:00
parent e94b446eac
commit 050ef43ec7
4 changed files with 58 additions and 1 deletions

View file

@ -25,6 +25,7 @@
enum clock_properties { enum clock_properties {
CLOCK_PROP_HAS_SCALING = 1 << 0, CLOCK_PROP_HAS_SCALING = 1 << 0,
CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1,
}; };
static int msm_vidc_populate_legacy_context_bank( static int msm_vidc_populate_legacy_context_bank(
struct msm_vidc_platform_resources *res); struct msm_vidc_platform_resources *res);
@ -943,6 +944,11 @@ static int msm_vidc_load_clock_table(
vc->has_scaling = false; vc->has_scaling = false;
} }
if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION)
vc->has_mem_retention = true;
else
vc->has_mem_retention = false;
dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name, dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name,
vc->count ? "yes" : "no"); vc->count ? "yes" : "no");
} }

View file

@ -104,6 +104,7 @@ struct clock_info {
struct load_freq_table *load_freq_tbl; struct load_freq_table *load_freq_tbl;
u32 count; u32 count;
bool has_scaling; bool has_scaling;
bool has_mem_retention;
}; };
struct clock_set { struct clock_set {

View file

@ -3796,6 +3796,22 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device)
if (cl->has_scaling) if (cl->has_scaling)
clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0)); clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0));
if (cl->has_mem_retention) {
rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH);
if (rc) {
dprintk(VIDC_WARN,
"Failed set flag NORETAIN_PERIPH %s\n",
cl->name);
}
rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM);
if (rc) {
dprintk(VIDC_WARN,
"Failed set flag NORETAIN_MEM %s\n",
cl->name);
}
}
rc = clk_prepare_enable(cl->clk); rc = clk_prepare_enable(cl->clk);
if (rc) { if (rc) {
dprintk(VIDC_ERR, "Failed to enable clocks\n"); dprintk(VIDC_ERR, "Failed to enable clocks\n");

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -15,6 +15,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/msm-clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
@ -111,6 +112,7 @@ struct vmem {
struct { struct {
const char *name; const char *name;
struct clk *clk; struct clk *clk;
bool has_mem_retention;
} *clocks; } *clocks;
int num_clocks; int num_clocks;
struct { struct {
@ -186,6 +188,21 @@ static inline int __power_on(struct vmem *v)
pr_debug("Enabled regulator vdd\n"); pr_debug("Enabled regulator vdd\n");
for (c = 0; c < v->num_clocks; ++c) { for (c = 0; c < v->num_clocks; ++c) {
if (v->clocks[c].has_mem_retention) {
rc = clk_set_flags(v->clocks[c].clk,
CLKFLAG_NORETAIN_PERIPH);
if (rc) {
pr_warn("Failed set flag NORETAIN_PERIPH %s\n",
v->clocks[c].name);
}
rc = clk_set_flags(v->clocks[c].clk,
CLKFLAG_NORETAIN_MEM);
if (rc) {
pr_warn("Failed set flag NORETAIN_MEM %s\n",
v->clocks[c].name);
}
}
rc = clk_prepare_enable(v->clocks[c].clk); rc = clk_prepare_enable(v->clocks[c].clk);
if (rc) { if (rc) {
pr_err("Failed to enable %s clock (%d)\n", pr_err("Failed to enable %s clock (%d)\n",
@ -448,6 +465,7 @@ static inline int __init_resources(struct vmem *v,
struct platform_device *pdev) struct platform_device *pdev)
{ {
int rc = 0, c = 0; int rc = 0, c = 0;
int *clock_props = NULL;
v->irq = platform_get_irq(pdev, 0); v->irq = platform_get_irq(pdev, 0);
if (v->irq < 0) { if (v->irq < 0) {
@ -504,6 +522,21 @@ static inline int __init_resources(struct vmem *v,
goto exit; goto exit;
} }
clock_props = devm_kzalloc(&pdev->dev,
v->num_clocks * sizeof(*clock_props),
GFP_KERNEL);
if (!clock_props) {
pr_err("Failed to allocate clock config table\n");
goto exit;
}
rc = of_property_read_u32_array(pdev->dev.of_node, "clock-config",
clock_props, v->num_clocks);
if (rc) {
pr_err("Failed to read clock config\n");
goto exit;
}
for (c = 0; c < v->num_clocks; ++c) { for (c = 0; c < v->num_clocks; ++c) {
const char *name = NULL; const char *name = NULL;
struct clk *temp = NULL; struct clk *temp = NULL;
@ -519,6 +552,7 @@ static inline int __init_resources(struct vmem *v,
v->clocks[c].clk = temp; v->clocks[c].clk = temp;
v->clocks[c].name = name; v->clocks[c].name = name;
v->clocks[c].has_mem_retention = clock_props[c];
} }
v->vdd = devm_regulator_get(&pdev->dev, "vdd"); v->vdd = devm_regulator_get(&pdev->dev, "vdd");