summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShen Yong <b00984@freescale.com>2010-08-24 11:44:58 +0800
committerShen Yong <b00984@freescale.com>2010-08-27 15:21:13 +0800
commit918cf47819220623df3bf0447d9a3674cd2c3ee6 (patch)
tree97ed7f737e3d89d4f64868f33a7bc4c9d34d9112
parent7c26dc7f75e59ecf1098a506936b2f7dcc7f8ccc (diff)
ENGR00126307 mx53: implement low bus frequency mode
implement low bus frequency mode in busfreq driver, and also adjust setting of ccm register to achieve more power efficience Signed-off-by: Shen Yong <b00984@freescale.com>
-rw-r--r--arch/arm/mach-mx5/bus_freq.c141
-rw-r--r--arch/arm/mach-mx5/clock.c16
2 files changed, 138 insertions, 19 deletions
diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c
index 4fcaf95e3019..49e50d08bb60 100644
--- a/arch/arm/mach-mx5/bus_freq.c
+++ b/arch/arm/mach-mx5/bus_freq.c
@@ -41,6 +41,8 @@
#define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
#define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV
#define NFC_CLK_NORMAL_DIV 4
+#define SPIN_DELAY 1000000 /* in nanoseconds */
+
static unsigned long lp_normal_rate;
static unsigned long lp_med_rate;
@@ -49,8 +51,10 @@ static unsigned long ddr_low_rate;
static struct clk *ddr_clk;
static struct clk *pll1_sw_clk;
+static struct clk *pll1;
static struct clk *pll2;
static struct clk *pll3;
+static struct clk *pll4;
static struct clk *main_bus_clk;
static struct clk *axi_a_clk;
static struct clk *axi_b_clk;
@@ -79,6 +83,7 @@ char *lp_reg_id = "SW2";
static struct cpu_wp *cpu_wp_tbl;
static struct device *busfreq_dev;
static int busfreq_suspended;
+static int cpu_podf;
/* True if bus_frequency is scaled not using DVFS-PER */
int bus_freq_scaling_is_active;
@@ -88,6 +93,7 @@ int lp_med_freq;
extern int dvfs_core_is_active;
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
+extern void propagate_rate(struct clk *tclk);
struct dvfs_wp dvfs_core_setpoint[] = {
{33, 8, 33, 10, 10, 0x08},
@@ -95,9 +101,14 @@ struct dvfs_wp dvfs_core_setpoint[] = {
{28, 8, 33, 20, 30, 0x08},
{29, 0, 33, 20, 10, 0x08},};
+static void __iomem *pll1_base;
+static void __iomem *pll4_base;
+
int set_low_bus_freq(void)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (busfreq_suspended)
return 0;
@@ -107,10 +118,6 @@ int set_low_bus_freq(void)
if (clk_get_rate(cpu_clk) != cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
return 0;
- /* currently not support on mx53 */
- if (cpu_is_mx53())
- return 0;
-
stop_dvfs_per();
stop_sdram_autogating();
@@ -119,7 +126,7 @@ int set_low_bus_freq(void)
clk_round_rate(ddr_hf_clk, ddr_low_rate));
/* Set PLL3 to 133Mhz if no-one is using it. */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && cpu_is_mx51()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
@@ -159,7 +166,57 @@ int set_low_bus_freq(void)
low_bus_freq_mode = 1;
high_bus_freq_mode = 0;
+ } else {
+ /* move cpu clk to pll2, 400 / 3 = 133Mhz for cpu */
+ clk_set_parent(pll1_sw_clk, pll2);
+
+ cpu_podf = __raw_readl(MXC_CCM_CACRR);
+ reg = __raw_readl(MXC_CCM_CDHIPR);
+ if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0)
+ __raw_writel(0x2, MXC_CCM_CACRR);
+ else
+ printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n");
+
+ /* ahb = 400/8, axi_b = 400/8, axi_a = 133*/
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK);
+ reg |= (2 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 7 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 7 << MXC_CCM_CBCDR_AHB_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ getnstimeofday(&nstimeofday);
+ while (__raw_readl(MXC_CCM_CDHIPR) &
+ (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY |
+ MXC_CCM_CDHIPR_AXI_B_PODF_BUSY |
+ MXC_CCM_CDHIPR_AHB_PODF_BUSY)) {
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec - nstimeofday.tv_nsec
+ > SPIN_DELAY)
+ panic("low bus freq set rate error\n");
+ }
+
+ /* keep this infront of propagating */
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
+
+ propagate_rate(main_bus_clk);
+ propagate_rate(pll1_sw_clk);
+
+ if (clk_get_usecount(pll1) == 0) {
+ reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL);
+ reg &= ~MXC_PLL_DP_CTL_UPEN;
+ __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL);
+ }
+ if (clk_get_usecount(pll4) == 0) {
+ reg = __raw_readl(pll4_base + MXC_PLL_DP_CTL);
+ reg &= ~MXC_PLL_DP_CTL_UPEN;
+ __raw_writel(reg, pll4_base + MXC_PLL_DP_CTL);
+ }
}
+
}
return 0;
}
@@ -167,6 +224,8 @@ int set_low_bus_freq(void)
int set_high_bus_freq(int high_bus_freq)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (bus_freq_scaling_initialized) {
@@ -174,7 +233,7 @@ int set_high_bus_freq(int high_bus_freq)
if (low_bus_freq_mode) {
/* Relock PLL3 to 133MHz */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && cpu_is_mx51()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
@@ -210,9 +269,49 @@ int set_high_bus_freq(int high_bus_freq)
clk_set_rate(pll3,
clk_round_rate(pll3, pll3_rate));
clk_disable(pll3);
+ } else {
+ /* move cpu clk to pll1 */
+ reg = __raw_readl(MXC_CCM_CDHIPR);
+ if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0)
+ __raw_writel(cpu_podf & 0x7,
+ MXC_CCM_CACRR);
+ else
+ printk(KERN_DEBUG
+ "ARM_PODF still in busy!!!!\n");
+
+ clk_set_parent(pll1_sw_clk, pll1);
+
+ /* ahb = 400/3, axi_b = 400/3, axi_a = 400*/
+ reg = __raw_readl(MXC_CCM_CBCDR);
+ reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK
+ | MXC_CCM_CBCDR_AXI_B_PODF_MASK
+ | MXC_CCM_CBCDR_AHB_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 2 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ getnstimeofday(&nstimeofday);
+ while (__raw_readl(MXC_CCM_CDHIPR) &
+ (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY |
+ MXC_CCM_CDHIPR_AXI_B_PODF_BUSY |
+ MXC_CCM_CDHIPR_AHB_PODF_BUSY)) {
+ getnstimeofday(&curtime);
+ if (curtime.tv_nsec
+ - nstimeofday.tv_nsec
+ > SPIN_DELAY)
+ panic("bus freq error\n");
+ }
+
+ /* keep this infront of propagating */
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
+
+ propagate_rate(main_bus_clk);
+ propagate_rate(pll1_sw_clk);
}
- /*Change the DDR freq to 200MHz*/
+ /*Change the DDR freq to mormal_rate*/
clk_set_rate(ddr_hf_clk,
clk_round_rate(ddr_hf_clk, ddr_normal_rate));
@@ -286,8 +385,7 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
{
u32 reg;
-
- if (strstr(buf, "1") != NULL) {
+ if (strncmp(buf, "1", 1) == 0) {
if (dvfs_per_active()) {
printk(KERN_INFO "bus frequency scaling cannot be\
enabled when DVFS-PER is active\n");
@@ -302,12 +400,12 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
bus_freq_scaling_is_active = 1;
set_high_bus_freq(0);
- }
- else if (strstr(buf, "0") != NULL) {
+ } else if (strncmp(buf, "0", 1) == 0) {
if (bus_freq_scaling_is_active)
set_high_bus_freq(1);
bus_freq_scaling_is_active = 0;
}
+
return size;
}
@@ -341,6 +439,9 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
int err = 0;
unsigned long pll2_rate, pll1_rate;
+ pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K);
+ pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K);
+
busfreq_dev = &pdev->dev;
main_bus_clk = clk_get(NULL, "main_bus_clk");
@@ -356,12 +457,30 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(pll1_sw_clk);
}
+ pll1 = clk_get(NULL, "pll1_main_clk");
+ if (IS_ERR(pll1)) {
+ printk(KERN_DEBUG "%s: failed to get pll1\n", __func__);
+ return PTR_ERR(pll1);
+ }
+
pll2 = clk_get(NULL, "pll2");
if (IS_ERR(pll2)) {
printk(KERN_DEBUG "%s: failed to get pll2\n", __func__);
return PTR_ERR(pll2);
}
+ pll3 = clk_get(NULL, "pll3");
+ if (IS_ERR(pll3)) {
+ printk(KERN_DEBUG "%s: failed to get pll3\n", __func__);
+ return PTR_ERR(pll3);
+ }
+
+ pll4 = clk_get(NULL, "pll4");
+ if (IS_ERR(pll4)) {
+ printk(KERN_DEBUG "%s: failed to get pll4\n", __func__);
+ return PTR_ERR(pll4);
+ }
+
pll1_rate = clk_get_rate(pll1_sw_clk);
pll2_rate = clk_get_rate(pll2);
diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c
index e119ecf69500..2414e8d235a1 100644
--- a/arch/arm/mach-mx5/clock.c
+++ b/arch/arm/mach-mx5/clock.c
@@ -4731,17 +4731,17 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long
1 << MXC_CCM_CCGR5_CG6_OFFSET |
3 << MXC_CCM_CCGR5_CG7_OFFSET |
1 << MXC_CCM_CCGR5_CG8_OFFSET |
- 3 << MXC_CCM_CCGR5_CG9_OFFSET |
+ 1 << MXC_CCM_CCGR5_CG9_OFFSET |
1 << MXC_CCM_CCGR5_CG10_OFFSET |
3 << MXC_CCM_CCGR5_CG11_OFFSET, MXC_CCM_CCGR5);
- __raw_writel(3 << MXC_CCM_CCGR6_CG0_OFFSET |
- 3 << MXC_CCM_CCGR6_CG1_OFFSET |
- 3 << MXC_CCM_CCGR6_CG4_OFFSET |
- 3 << MXC_CCM_CCGR6_CG8_OFFSET |
- 3 << MXC_CCM_CCGR6_CG9_OFFSET |
- 3 << MXC_CCM_CCGR6_CG12_OFFSET |
- 3 << MXC_CCM_CCGR6_CG13_OFFSET , MXC_CCM_CCGR6);
+ __raw_writel(1 << MXC_CCM_CCGR6_CG0_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG1_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG4_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG8_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG9_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG12_OFFSET |
+ 1 << MXC_CCM_CCGR6_CG13_OFFSET , MXC_CCM_CCGR6);
__raw_writel(0, MXC_CCM_CCGR7);