Commit 74474dc3 authored by Anson Huang's avatar Anson Huang

ENGR00220370 [MX6]Fix BUS freq suspend/resume fail in low bus mode

1. BUS freq's set low bus setpoint using delat work, which
didn't have mutex lock, so in some scenarios, set high bus
freq function can be called at the same time, we need to move
mutex lock into these two routine;

2. Using pm notify to make sure bus freq set to high setpoint
before supend and restore after resume.

3. Clear build warning.
Signed-off-by: default avatarAnson Huang <b20788@freescale.com>
parent 759217f2
......@@ -1505,11 +1505,10 @@ static struct gpio_led imx6q_gpio_leds[] = {
/* For the latest B4 board, this GPIO_1 is connected to POR_B,
which will reset the whole board if this pin's level is changed,
so, for the latest board, we have to avoid using this pin as
GPIO. */
#if 0
GPIO.
GPIO_LED(SABRESD_CHARGE_DONE, "chg_done_led", 0, 1,
"charger-full"),
#endif
*/
};
static struct gpio_led_platform_data imx6q_gpio_leds_data = {
......
......@@ -44,6 +44,7 @@
#include <asm/cacheflush.h>
#include <asm/tlb.h>
#include "crm_regs.h"
#include <linux/suspend.h>
#define LPAPM_CLK 24000000
#define DDR_MED_CLK 400000000
......@@ -111,11 +112,16 @@ static struct delayed_work low_bus_freq_handler;
static void reduce_bus_freq_handler(struct work_struct *work)
{
if (low_bus_freq_mode || !low_freq_bus_used())
mutex_lock(&bus_freq_mutex);
if (low_bus_freq_mode || !low_freq_bus_used()) {
mutex_unlock(&bus_freq_mutex);
return;
}
if (audio_bus_freq_mode && lp_audio_freq)
if (audio_bus_freq_mode && lp_audio_freq) {
mutex_unlock(&bus_freq_mutex);
return;
}
if (!cpu_is_mx6sl()) {
clk_enable(pll3);
......@@ -181,6 +187,7 @@ static void reduce_bus_freq_handler(struct work_struct *work)
}
high_bus_freq_mode = 0;
mutex_unlock(&bus_freq_mutex);
}
/* Set the DDR, AHB to 24MHz.
......@@ -207,29 +214,42 @@ int set_low_bus_freq(void)
*/
int set_high_bus_freq(int high_bus_freq)
{
if (busfreq_suspended)
if (bus_freq_scaling_initialized && bus_freq_scaling_is_active)
cancel_delayed_work_sync(&low_bus_freq_handler);
mutex_lock(&bus_freq_mutex);
if (busfreq_suspended) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if (high_bus_freq_mode && high_bus_freq)
if (high_bus_freq_mode && high_bus_freq) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if (med_bus_freq_mode && !high_bus_freq)
if (med_bus_freq_mode && !high_bus_freq) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if (cpu_is_mx6dl() && high_bus_freq)
high_bus_freq = 0;
if (cpu_is_mx6dl() && med_bus_freq_mode)
if (cpu_is_mx6dl() && med_bus_freq_mode) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if ((high_bus_freq_mode && (high_bus_freq || lp_high_freq)) ||
(med_bus_freq_mode && !high_bus_freq && lp_med_freq &&
!lp_high_freq))
!lp_high_freq)) {
mutex_unlock(&bus_freq_mutex);
return 0;
}
if (cpu_is_mx6sl()) {
u32 reg;
unsigned long flags;
......@@ -291,6 +311,7 @@ int set_high_bus_freq(int high_bus_freq)
if (cpu_is_mx6sl())
arm_mem_clked_in_wait = false;
mutex_unlock(&bus_freq_mutex);
return 0;
}
......@@ -339,15 +360,21 @@ void bus_freq_update(struct clk *clk, bool flag)
}
} else {
if ((clk->flags & AHB_MED_SET_POINT)
&& !med_bus_freq_mode)
&& !med_bus_freq_mode) {
/* Set to Medium setpoint */
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(0);
return;
}
else if ((clk->flags & AHB_HIGH_SET_POINT)
&& !high_bus_freq_mode)
&& !high_bus_freq_mode) {
/* Currently at low or medium set point,
* need to set to high setpoint
*/
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(1);
return;
}
}
}
} else {
......@@ -363,12 +390,16 @@ void bus_freq_update(struct clk *clk, bool flag)
&& (clk_get_usecount(clk) == 0)) {
if (low_freq_bus_used() && !low_bus_freq_mode)
set_low_bus_freq();
else
else {
/* Set to either high or medium setpoint. */
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(0);
return;
}
}
}
mutex_unlock(&bus_freq_mutex);
return;
}
void setup_pll(void)
{
......@@ -404,16 +435,28 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
static int busfreq_suspend(struct platform_device *pdev, pm_message_t message)
{
set_high_bus_freq(1);
busfreq_suspended = 1;
return 0;
}
static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event,
void *dummy)
{
if (event == PM_SUSPEND_PREPARE) {
set_high_bus_freq(1);
busfreq_suspended = 1;
} else if (event == PM_POST_SUSPEND) {
busfreq_suspended = 0;
}
return NOTIFY_OK;
}
static int busfreq_resume(struct platform_device *pdev)
{
busfreq_suspended = 0;
return 0;
}
static struct notifier_block imx_bus_freq_pm_notifier = {
.notifier_call = bus_freq_pm_notify,
};
static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
bus_freq_scaling_enable_store);
......@@ -570,6 +613,7 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
}
INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler);
register_pm_notifier(&imx_bus_freq_pm_notifier);
if (!cpu_is_mx6sl())
init_mmdc_settings();
......
......@@ -1280,11 +1280,6 @@ static int _clk_arm_set_rate(struct clk *clk, unsigned long rate)
else
pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk);
}
if (cpu_op_tbl[i].cpu_podf) {
__raw_writel(cpu_op_tbl[i].cpu_podf, MXC_CCM_CACRR);
while (__raw_readl(MXC_CCM_CDHIPR))
;
}
pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate);
}
/* Make sure pll1_sw_clk is from pll1_sys_main_clk */
......@@ -2005,7 +2000,7 @@ static struct clk vdoa_clk[] = {
},
};
static unsigned long mx6_timer_rate()
static unsigned long mx6_timer_rate(void)
{
u32 parent_rate = clk_get_rate(&osc_clk);
......
......@@ -96,9 +96,11 @@ int set_cpu_freq(int freq)
/*Set the voltage for the GP domain. */
if (freq > org_cpu_rate) {
mutex_lock(&bus_freq_mutex);
if (low_bus_freq_mode || audio_bus_freq_mode)
if (low_bus_freq_mode || audio_bus_freq_mode) {
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(0);
mutex_unlock(&bus_freq_mutex);
} else
mutex_unlock(&bus_freq_mutex);
if (freq == cpu_op_tbl[0].cpu_rate && !IS_ERR(soc_regulator) && !IS_ERR(pu_regulator)) {
ret = regulator_set_voltage(soc_regulator, soc_volt,
soc_volt);
......
......@@ -647,22 +647,22 @@ static void dvfs_core_work_handler(struct work_struct *work)
mutex_lock(&bus_freq_mutex);
if ((curr_op == cpu_op_nr - 1) && (!low_bus_freq_mode)
&& (low_freq_bus_ready) && !bus_incr) {
mutex_unlock(&bus_freq_mutex);
if (!minf)
set_cpu_freq(curr_op);
/* If dvfs_core_op is greater than cpu_op_nr, it implies
* we support LPAPM mode for this platform.
*/
if (dvfs_core_op > cpu_op_nr) {
mutex_lock(&bus_freq_mutex);
set_low_bus_freq();
mutex_unlock(&bus_freq_mutex);
dvfs_load_config(cpu_op_nr + 1);
}
mutex_unlock(&bus_freq_mutex);
} else {
if (!high_bus_freq_mode)
if (!high_bus_freq_mode) {
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(1);
mutex_unlock(&bus_freq_mutex);
} else
mutex_unlock(&bus_freq_mutex);
if (!bus_incr)
ret = set_cpu_freq(curr_op);
bus_incr = 0;
......@@ -735,9 +735,11 @@ void stop_dvfs(void)
curr_op = 0;
mutex_lock(&bus_freq_mutex);
if (!high_bus_freq_mode)
if (!high_bus_freq_mode) {
mutex_unlock(&bus_freq_mutex);
set_high_bus_freq(1);
mutex_unlock(&bus_freq_mutex);
} else
mutex_unlock(&bus_freq_mutex);
curr_cpu = clk_get_rate(cpu_clk);
if (curr_cpu != cpu_op_tbl[curr_op].cpu_rate) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment