diff options
author | Anson Huang <b20788@freescale.com> | 2015-01-01 00:27:58 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2015-02-02 14:47:20 +0800 |
commit | 96391f1b6535f8856149ebd8632c72e4561efdcf (patch) | |
tree | e83dbdff59ff461435bcfadf0626e627047685e5 /drivers | |
parent | ae2c25ec6cf9810f0978d24bbc6d4f2f423863f9 (diff) |
MLK-10033 cpufreq: cpufreq-imx6: add cpufreq mutex for regulator enable/disable
System may hang if cpufreq is updated during pu enable/disable flow, add cpufreq
mutex in before vddpu regulator enable/disable to make sure no any break happen.
Unfortunetly, there is no better way on v3.10 since both PU management and cpufreq
are based on regulator framework.
Another change is increasing cpufreq to the highest setpoint and then disable
cpufreq.That makes sure no any mutex OOps before reboot, such as cpufreq update thread
is killed after get cpufreq mutex while xPU driver fall into PU enable/disable flow.
Signed-off-by: Anson Huang <b20788@freescale.com>
Signed-off-by: Robin Gong <b38343@freescale.com>
(cherry picked from commit a43de999958a30a04f1df13475bc69b432c05308)
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/cpufreq/cpufreq-imx6.c | 31 | ||||
-rw-r--r-- | drivers/regulator/core.c | 15 |
2 files changed, 41 insertions, 5 deletions
diff --git a/drivers/cpufreq/cpufreq-imx6.c b/drivers/cpufreq/cpufreq-imx6.c index 10bd0b764437..65a4aeddbc7d 100644 --- a/drivers/cpufreq/cpufreq-imx6.c +++ b/drivers/cpufreq/cpufreq-imx6.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/opp.h> +#include <linux/reboot.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -32,7 +33,7 @@ static struct clk *pll2_pfd2_396m_clk; static struct device *cpu_dev; static struct cpufreq_frequency_table *freq_table; static unsigned int transition_latency; -static struct mutex set_cpufreq_lock; +DEFINE_MUTEX(set_cpufreq_lock); struct soc_opp { u32 arm_freq; @@ -41,6 +42,7 @@ struct soc_opp { static struct soc_opp *imx6_soc_opp; static u32 soc_opp_count; +static int num; static int imx6_verify_speed(struct cpufreq_policy *policy) { @@ -290,12 +292,33 @@ static struct notifier_block imx6_cpufreq_pm_notifier = { .notifier_call = imx6_cpufreq_pm_notify, }; +static int imx6_cpufreq_reboot_notify(struct notifier_block *this, + unsigned long event, void *dummy) +{ + struct cpufreq_policy *data = cpufreq_cpu_get(0); + + /* raise up cpu clock to the highest setpoint before reboot */ + if (event == SYS_RESTART || event == SYS_HALT || + event == SYS_POWER_OFF) { + data->user_policy.min = data->user_policy.max = + freq_table[num - 1].frequency; + cpufreq_update_policy(0); + disable_cpufreq(); + } + + return NOTIFY_OK; +} + +static struct notifier_block imx6_cpufreq_reboot_notifier = { + .notifier_call = imx6_cpufreq_reboot_notify, +}; + static int imx6_cpufreq_probe(struct platform_device *pdev) { struct device_node *np; struct opp *opp; unsigned long min_volt = 0, max_volt = 0; - int num, ret; + int ret; const struct property *prop; const __be32 *val; u32 nr, i = 0; @@ -459,8 +482,8 @@ static int imx6_cpufreq_probe(struct platform_device *pdev) if (ret > 0) transition_latency += ret * 1000; - mutex_init(&set_cpufreq_lock); register_pm_notifier(&imx6_cpufreq_pm_notifier); + register_reboot_notifier(&imx6_cpufreq_reboot_notifier); ret = cpufreq_register_driver(&imx6_cpufreq_driver); if (ret) { diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index afc83e105b26..df87ce7cf6b1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3,7 +3,7 @@ * * Copyright 2007, 2008 Wolfson Microelectronics PLC. * Copyright 2008 SlimLogic Ltd. - * Copyright (C) 2013 Freescale Semiconductor, Inc. + * Copyright (C) 2015 Freescale Semiconductor, Inc. * * Author: Liam Girdwood <lrg@slimlogic.co.uk> * @@ -1669,6 +1669,7 @@ static int _regulator_enable(struct regulator_dev *rdev) * NOTE: the output value can be set by other drivers, boot loader or may be * hardwired in the regulator. */ +extern struct mutex set_cpufreq_lock; int regulator_enable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; @@ -1683,10 +1684,16 @@ int regulator_enable(struct regulator *regulator) return ret; } + if (!strcmp(rdev->desc->name, "vddpu")) + mutex_lock(&set_cpufreq_lock); + mutex_lock(&rdev->mutex); ret = _regulator_enable(rdev); mutex_unlock(&rdev->mutex); + if (!strcmp(rdev->desc->name, "vddpu")) + mutex_unlock(&set_cpufreq_lock); + if (ret != 0 && rdev->supply) regulator_disable(rdev->supply); @@ -1776,10 +1783,16 @@ int regulator_disable(struct regulator *regulator) if (regulator->always_on) return 0; + if (!strcmp(rdev->desc->name, "vddpu")) + mutex_lock(&set_cpufreq_lock); + mutex_lock(&rdev->mutex); ret = _regulator_disable(rdev); mutex_unlock(&rdev->mutex); + if (!strcmp(rdev->desc->name, "vddpu")) + mutex_unlock(&set_cpufreq_lock); + if (ret == 0 && rdev->supply) regulator_disable(rdev->supply); |