commit b25af2ff7c07bd19af74e3f64ff82e2880d13d81 upstream. Since commit 1e434b703248 ("ARM: imx: update the cpu power up timing setting on i.mx6sx") some characters loss is noticed on i.MX6ULL UART as reported by Christoph Niedermaier. The intention of such commit was to increase the SW2ISO field for i.MX6SX only, but since cpuidle-imx6sx is also used on i.MX6UL/i.MX6ULL this caused unintended side effects on other SoCs. Fix this problem by keeping the original SW2ISO value for i.MX6UL/i.MX6ULL and only increase SW2ISO in the i.MX6SX case. Cc: stable@vger.kernel.org Fixes: 1e434b703248 ("ARM: imx: update the cpu power up timing setting on i.mx6sx") Reported-by: Christoph Niedermaier <cniedermaier@dh-electronics.com> Signed-off-by: Fabio Estevam <festevam@gmail.com> Tested-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com> Tested-by: Christoph Niedermaier <cniedermaier@dh-electronics.com> Signed-off-by: Shawn Guo <shawnguo@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
106 lines
2.2 KiB
C
106 lines
2.2 KiB
C
/*
|
|
* Copyright (C) 2014 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
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/cpuidle.h>
|
|
#include <linux/cpu_pm.h>
|
|
#include <linux/module.h>
|
|
#include <asm/cpuidle.h>
|
|
#include <asm/suspend.h>
|
|
|
|
#include "common.h"
|
|
#include "cpuidle.h"
|
|
#include "hardware.h"
|
|
|
|
static int imx6sx_idle_finish(unsigned long val)
|
|
{
|
|
cpu_do_idle();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int imx6sx_enter_wait(struct cpuidle_device *dev,
|
|
struct cpuidle_driver *drv, int index)
|
|
{
|
|
imx6_set_lpm(WAIT_UNCLOCKED);
|
|
|
|
switch (index) {
|
|
case 1:
|
|
cpu_do_idle();
|
|
break;
|
|
case 2:
|
|
imx6_enable_rbc(true);
|
|
imx_gpc_set_arm_power_in_lpm(true);
|
|
imx_set_cpu_jump(0, v7_cpu_resume);
|
|
/* Need to notify there is a cpu pm operation. */
|
|
cpu_pm_enter();
|
|
cpu_cluster_pm_enter();
|
|
|
|
cpu_suspend(0, imx6sx_idle_finish);
|
|
|
|
cpu_cluster_pm_exit();
|
|
cpu_pm_exit();
|
|
imx_gpc_set_arm_power_in_lpm(false);
|
|
imx6_enable_rbc(false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
imx6_set_lpm(WAIT_CLOCKED);
|
|
|
|
return index;
|
|
}
|
|
|
|
static struct cpuidle_driver imx6sx_cpuidle_driver = {
|
|
.name = "imx6sx_cpuidle",
|
|
.owner = THIS_MODULE,
|
|
.states = {
|
|
/* WFI */
|
|
ARM_CPUIDLE_WFI_STATE,
|
|
/* WAIT */
|
|
{
|
|
.exit_latency = 50,
|
|
.target_residency = 75,
|
|
.flags = CPUIDLE_FLAG_TIMER_STOP,
|
|
.enter = imx6sx_enter_wait,
|
|
.name = "WAIT",
|
|
.desc = "Clock off",
|
|
},
|
|
/* WAIT + ARM power off */
|
|
{
|
|
/*
|
|
* ARM gating 31us * 5 + RBC clear 65us
|
|
* and some margin for SW execution, here set it
|
|
* to 300us.
|
|
*/
|
|
.exit_latency = 300,
|
|
.target_residency = 500,
|
|
.enter = imx6sx_enter_wait,
|
|
.name = "LOW-POWER-IDLE",
|
|
.desc = "ARM power off",
|
|
},
|
|
},
|
|
.state_count = 3,
|
|
.safe_state_index = 0,
|
|
};
|
|
|
|
int __init imx6sx_cpuidle_init(void)
|
|
{
|
|
imx6_enable_rbc(false);
|
|
/*
|
|
* set ARM power up/down timing to the fastest,
|
|
* sw2iso and sw can be set to one 32K cycle = 31us
|
|
* except for power up sw2iso which need to be
|
|
* larger than LDO ramp up time.
|
|
*/
|
|
imx_gpc_set_arm_power_up_timing(cpu_is_imx6sx() ? 0xf : 0x2, 1);
|
|
imx_gpc_set_arm_power_down_timing(1, 1);
|
|
|
|
return cpuidle_register(&imx6sx_cpuidle_driver, NULL);
|
|
}
|