summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/dvfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/dvfs.c')
-rw-r--r--arch/arm/mach-tegra/dvfs.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c
index 7d396ca98c21..dd97e6944fe3 100644
--- a/arch/arm/mach-tegra/dvfs.c
+++ b/arch/arm/mach-tegra/dvfs.c
@@ -232,6 +232,7 @@ static int dvfs_rail_update(struct dvfs_rail *rail)
struct dvfs *d;
struct dvfs_relationship *rel;
int ret = 0;
+ int steps;
/* if dvfs is suspended, return and handle it during resume */
if (rail->suspended)
@@ -250,14 +251,21 @@ static int dvfs_rail_update(struct dvfs_rail *rail)
list_for_each_entry(d, &rail->dvfs, reg_node)
millivolts = max(d->cur_millivolts, millivolts);
- rail->new_millivolts = millivolts;
+ /* retry update if limited by from-relationship to account for
+ circular dependencies */
+ steps = DIV_ROUND_UP(abs(millivolts - rail->millivolts), rail->step);
+ for (; steps >= 0; steps--) {
+ rail->new_millivolts = millivolts;
- /* Check any rails that this rail depends on */
- list_for_each_entry(rel, &rail->relationships_from, from_node)
- rail->new_millivolts = dvfs_solve_relationship(rel);
+ /* Check any rails that this rail depends on */
+ list_for_each_entry(rel, &rail->relationships_from, from_node)
+ rail->new_millivolts = dvfs_solve_relationship(rel);
+
+ if (rail->new_millivolts == rail->millivolts)
+ break;
- if (rail->new_millivolts != rail->millivolts)
ret = dvfs_rail_set_voltage(rail, rail->new_millivolts);
+ }
return ret;
}