summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx5/bus_freq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mx5/bus_freq.c')
-rw-r--r--arch/arm/mach-mx5/bus_freq.c582
1 files changed, 445 insertions, 137 deletions
diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c
index 4ab60ec6386d..ec2addfd977b 100644
--- a/arch/arm/mach-mx5/bus_freq.c
+++ b/arch/arm/mach-mx5/bus_freq.c
@@ -27,45 +27,56 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/iram_alloc.h>
+#include <linux/mutex.h>
#include <mach/hardware.h>
#include <mach/clock.h>
#include <mach/mxc_dvfs.h>
#include <mach/sdram_autogating.h>
+#include <asm/mach/map.h>
+#include <asm/cacheflush.h>
+#include <asm/tlb.h>
#include "crm_regs.h"
-#define LP_NORMAL_CLK 133000000
-#define LP_MED_CLK 83125000
+#define LP_LOW_VOLTAGE 1050000
+#define LP_NORMAL_VOLTAGE 1250000
#define LP_APM_CLK 24000000
#define NAND_LP_APM_CLK 12000000
-#define DDR_LOW_FREQ_CLK 133000000
-#define DDR_NORMAL_CLK 200000000
#define AXI_A_NORMAL_CLK 166250000
#define AXI_A_CLK_NORMAL_DIV 4
#define AXI_B_CLK_NORMAL_DIV 5
#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 */
+
+DEFINE_SPINLOCK(ddr_freq_lock);
+
+static unsigned long lp_normal_rate;
+static unsigned long lp_med_rate;
+static unsigned long ddr_normal_rate;
+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;
static struct clk *cpu_clk;
static struct clk *ddr_hf_clk;
-static struct clk *nfc_clk;
static struct clk *ahb_clk;
-static struct clk *vpu_clk;
-static struct clk *vpu_core_clk;
-static struct clk *emi_slow_clk;
static struct clk *ddr_clk;
-static struct clk *ipu_clk;
static struct clk *periph_apm_clk;
static struct clk *lp_apm;
static struct clk *osc;
static struct clk *gpc_dvfs_clk;
static struct clk *emi_garb_clk;
+static void __iomem *pll1_base;
+static void __iomem *pll4_base;
struct regulator *lp_regulator;
int low_bus_freq_mode;
@@ -77,14 +88,28 @@ 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;
-extern int lp_high_freq;
-extern int lp_med_freq;
+int cpu_wp_nr;
+int lp_high_freq;
+int lp_med_freq;
+
+void enter_lpapm_mode_mx50(void);
+void enter_lpapm_mode_mx51(void);
+void exit_lpapm_mode_mx50(void);
+void exit_lpapm_mode_mx51(void);
+void *ddr_freq_change_iram_base;
+void (*change_ddr_freq)(void *ccm_addr, void *databahn_addr, u32 freq) = NULL;
+
+extern void mx50_ddr_freq_change(u32 ccm_base,
+ u32 databahn_addr, u32 freq);
extern int dvfs_core_is_active;
extern struct cpu_wp *(*get_cpu_wp)(int *wp);
-extern int cpu_wp_nr;
+extern void propagate_rate(struct clk *tclk);
+extern void __iomem *ccm_base;
+extern void __iomem *databahn_base;
struct dvfs_wp dvfs_core_setpoint[] = {
{33, 8, 33, 10, 10, 0x08},
@@ -92,121 +117,267 @@ struct dvfs_wp dvfs_core_setpoint[] = {
{28, 8, 33, 20, 30, 0x08},
{29, 0, 33, 20, 10, 0x08},};
-
int set_low_bus_freq(void)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (busfreq_suspended)
return 0;
if (bus_freq_scaling_initialized) {
- if (clk_get_rate(cpu_clk) != cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
+ /* can not enter low bus freq, when cpu is in highest freq */
+ if (clk_get_rate(cpu_clk) !=
+ cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) {
return 0;
+ }
stop_dvfs_per();
stop_sdram_autogating();
- /*Change the DDR freq to 133Mhz. */
- clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_LOW_FREQ_CLK));
-
/* Set PLL3 to 133Mhz if no-one is using it. */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
clk_set_rate(pll3, clk_round_rate(pll3, 133000000));
- /* Set the parent of Periph_apm_clk to be PLL3 */
- clk_set_parent(periph_apm_clk, pll3);
- clk_set_parent(main_bus_clk, periph_apm_clk);
-
- /* Set the AHB dividers to be 1. */
- /* Set the dividers to be 1, so the clock rates
- * are at 133MHz.
- */
- 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
- | MXC_CCM_CBCDR_EMI_PODF_MASK
- | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
- | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
- | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- __raw_writel(reg, MXC_CCM_CBCDR);
-
- clk_enable(emi_garb_clk);
- while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
- udelay(10);
- clk_disable(emi_garb_clk);
-
- /* Set the source of Periph_APM_Clock to be lp-apm. */
- clk_set_parent(periph_apm_clk, lp_apm);
+ if (cpu_is_mx50())
+ enter_lpapm_mode_mx50();
+ else
+ enter_lpapm_mode_mx51();
/* Set PLL3 back to original rate. */
clk_set_rate(pll3, clk_round_rate(pll3, pll3_rate));
clk_disable(pll3);
+ } else if (cpu_is_mx53()) {
+ /*Change the DDR freq to 133Mhz. */
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
+ /* 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;
}
+void enter_lpapm_mode_mx50()
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ddr_freq_lock, flags);
+
+ /* Set the parent of main_bus_clk to be PLL3 */
+ clk_set_parent(main_bus_clk, pll3);
+
+ /* Set the AHB dividers to be 1. */
+ /* Set the dividers to be 1, so the clock rates
+ * are at 133MHz.
+ */
+ 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
+ | MX50_CCM_CBCDR_WEIM_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F)
+ udelay(10);
+ low_bus_freq_mode = 1;
+ high_bus_freq_mode = 0;
+
+ /* Set the source of main_bus_clk to be lp-apm. */
+ clk_set_parent(main_bus_clk, lp_apm);
+
+ /* Set SYS_CLK to 24MHz. sourced from XTAL*/
+ /* Turn on the XTAL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg |= 3 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ /* Set the divider. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_DIV_XTAL_MASK;
+ reg |= 1 << MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ while (__raw_readl(MXC_CCM_CSR2) & 0x1)
+ udelay(10);
+
+ /* Set the source to be XTAL. */
+ reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS);
+ reg &= ~0x1;
+ __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS);
+ while (!(__raw_readl(MXC_CCM_CSR2) & 0x400))
+ udelay(10);
+
+ /* Turn OFF the PLL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ spin_unlock_irqrestore(&ddr_freq_lock, flags);
+
+}
+
+void enter_lpapm_mode_mx51()
+{
+ u32 reg;
+
+ /*Change the DDR freq to 133Mhz. */
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
+ /* Set the parent of Periph_apm_clk to be PLL3 */
+ clk_set_parent(periph_apm_clk, pll3);
+ clk_set_parent(main_bus_clk, periph_apm_clk);
+
+ /* Set the dividers to be 1, so the clock rates
+ * are at 133MHz.
+ */
+ 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
+ | MXC_CCM_CBCDR_EMI_PODF_MASK
+ | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
+ | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ clk_enable(emi_garb_clk);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
+ udelay(10);
+ clk_disable(emi_garb_clk);
+
+ /* Set the source of Periph_APM_Clock to be lp-apm. */
+ clk_set_parent(periph_apm_clk, lp_apm);
+}
+
int set_high_bus_freq(int high_bus_freq)
{
u32 reg;
+ struct timespec nstimeofday;
+ struct timespec curtime;
if (bus_freq_scaling_initialized) {
+
stop_sdram_autogating();
if (low_bus_freq_mode) {
/* Relock PLL3 to 133MHz */
- if (clk_get_usecount(pll3) == 0) {
+ if ((clk_get_usecount(pll3) == 0) && !cpu_is_mx53()) {
u32 pll3_rate = clk_get_rate(pll3);
clk_enable(pll3);
clk_set_rate(pll3,
clk_round_rate(pll3, 133000000));
- clk_set_parent(periph_apm_clk, pll3);
- /* Set the dividers to the default dividers */
+ if (cpu_is_mx50())
+ exit_lpapm_mode_mx50();
+ else
+ exit_lpapm_mode_mx51();
+
+ /* Relock PLL3 to its original rate */
+ clk_set_rate(pll3,
+ clk_round_rate(pll3, pll3_rate));
+ clk_disable(pll3);
+ } else if (cpu_is_mx53()) {
+ /* 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
- | MXC_CCM_CBCDR_EMI_PODF_MASK
- | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
- reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
- | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
- | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ | 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);
- clk_enable(emi_garb_clk);
- while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
- udelay(10);
-
- low_bus_freq_mode = 0;
- high_bus_freq_mode = 1;
- clk_disable(emi_garb_clk);
-
- /*Set the main_bus_clk parent to be PLL2. */
- clk_set_parent(main_bus_clk, pll2);
+ 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;
- /* Relock PLL3 to its original rate */
- clk_set_rate(pll3,
- clk_round_rate(pll3, pll3_rate));
- clk_disable(pll3);
+ propagate_rate(main_bus_clk);
+ propagate_rate(pll1_sw_clk);
+ /*Change the DDR freq to mormal_rate*/
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
}
-
- /*Change the DDR freq to 200MHz*/
- clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK));
start_dvfs_per();
}
if (bus_freq_scaling_is_active) {
@@ -218,24 +389,28 @@ int set_high_bus_freq(int high_bus_freq)
cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate)
high_bus_freq = 1;
- if (((clk_get_rate(ahb_clk) == LP_MED_CLK)
+ if (((clk_get_rate(ahb_clk) == lp_med_rate)
&& lp_high_freq) || high_bus_freq) {
/* Set to the high setpoint. */
high_bus_freq_mode = 1;
+
clk_set_rate(ahb_clk,
- clk_round_rate(ahb_clk, LP_NORMAL_CLK));
+ clk_round_rate(ahb_clk, lp_normal_rate));
+
clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk, DDR_NORMAL_CLK));
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
}
+
if (!lp_high_freq && !high_bus_freq) {
/* Set to the medium setpoint. */
high_bus_freq_mode = 0;
low_bus_freq_mode = 0;
+
clk_set_rate(ddr_hf_clk,
- clk_round_rate(ddr_hf_clk,
- DDR_LOW_FREQ_CLK));
+ clk_round_rate(ddr_hf_clk, ddr_low_rate));
+
clk_set_rate(ahb_clk,
- clk_round_rate(ahb_clk, LP_MED_CLK));
+ clk_round_rate(ahb_clk, lp_med_rate));
}
}
start_sdram_autogating();
@@ -243,11 +418,105 @@ int set_high_bus_freq(int high_bus_freq)
return 0;
}
+void exit_lpapm_mode_mx50()
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ddr_freq_lock, flags);
+
+ /* Set SYS_CLK to source from PLL1 */
+ /* Set sys_clk back to 200MHz. */
+ /* Set the divider to 4. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK;
+ reg |= 0x4 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+ udelay(100);
+
+ /* Turn ON the PLL CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg |= 3 << MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ /* Source the SYS_CLK from PLL */
+ reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS);
+ reg |= 0x3;
+ __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS);
+ while (__raw_readl(MXC_CCM_CSR2) & 0x400)
+ udelay(10);
+
+ /* Turn OFF the XTAL_CLK_GATE. */
+ reg = __raw_readl(MXC_CCM_CLK_SYS);
+ reg &= ~MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK;
+ __raw_writel(reg, MXC_CCM_CLK_SYS);
+
+ clk_set_parent(main_bus_clk, pll3);
+
+ /* Set the dividers to the default dividers */
+ 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
+ | MX50_CCM_CBCDR_WEIM_PODF_MASK);
+ reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0xF)
+ udelay(10);
+
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+
+ /*Set the main_bus_clk parent to be PLL2. */
+ clk_set_parent(main_bus_clk, pll2);
+ spin_unlock_irqrestore(&ddr_freq_lock, flags);
+
+ udelay(100);
+}
+
+void exit_lpapm_mode_mx51()
+{
+ u32 reg;
+
+ clk_set_parent(periph_apm_clk, pll3);
+
+ /* Set the dividers to the default dividers */
+ 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
+ | MXC_CCM_CBCDR_EMI_PODF_MASK
+ | MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET
+ | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET
+ | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET);
+ __raw_writel(reg, MXC_CCM_CBCDR);
+
+ clk_enable(emi_garb_clk);
+ while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F)
+ udelay(10);
+
+ low_bus_freq_mode = 0;
+ high_bus_freq_mode = 1;
+ clk_disable(emi_garb_clk);
+
+ /*Set the main_bus_clk parent to be PLL2. */
+ clk_set_parent(main_bus_clk, pll2);
+
+ /*Change the DDR freq to 200MHz*/
+ clk_set_rate(ddr_hf_clk,
+ clk_round_rate(ddr_hf_clk, ddr_normal_rate));
+}
+
int low_freq_bus_used(void)
{
- if ((clk_get_usecount(ipu_clk) == 0)
- && (clk_get_usecount(vpu_clk) == 0)
- && (lp_high_freq == 0)
+ if ((lp_high_freq == 0)
&& (lp_med_freq == 0))
return 1;
else
@@ -273,8 +542,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");
@@ -288,12 +556,13 @@ static ssize_t bus_freq_scaling_enable_store(struct device *dev,
clk_set_parent(main_bus_clk, pll2);
bus_freq_scaling_is_active = 1;
- }
- else if (strstr(buf, "0") != NULL) {
+ set_high_bus_freq(0);
+ } 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;
}
@@ -325,6 +594,12 @@ static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
static int __devinit busfreq_probe(struct platform_device *pdev)
{
int err = 0;
+ unsigned long pll2_rate, pll1_rate;
+ unsigned long iram_paddr;
+
+ pll1_base = ioremap(MX53_BASE_ADDR(PLL1_BASE_ADDR), SZ_4K);
+ if (cpu_is_mx53())
+ pll4_base = ioremap(MX53_BASE_ADDR(PLL4_BASE_ADDR), SZ_4K);
busfreq_dev = &pdev->dev;
@@ -335,6 +610,18 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(main_bus_clk);
}
+ pll1_sw_clk = clk_get(NULL, "pll1_sw_clk");
+ if (IS_ERR(pll1_sw_clk)) {
+ printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__);
+ 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__);
@@ -347,6 +634,14 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(pll3);
}
+ if (cpu_is_mx53()) {
+ pll4 = clk_get(NULL, "pll4");
+ if (IS_ERR(pll4)) {
+ printk(KERN_DEBUG "%s: failed to get pll4\n", __func__);
+ return PTR_ERR(pll4);
+ }
+ }
+
axi_a_clk = clk_get(NULL, "axi_a_clk");
if (IS_ERR(axi_a_clk)) {
printk(KERN_DEBUG "%s: failed to get axi_a_clk\n",
@@ -361,25 +656,19 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(axi_b_clk);
}
- ddr_hf_clk = clk_get(NULL, "ddr_hf_clk");
- if (IS_ERR(ddr_hf_clk)) {
- printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n",
+ ddr_clk = clk_get(NULL, "ddr_clk");
+ if (IS_ERR(ddr_clk)) {
+ printk(KERN_DEBUG "%s: failed to get ddr_clk\n",
__func__);
- return PTR_ERR(ddr_hf_clk);
+ return PTR_ERR(ddr_clk);
}
- emi_slow_clk = clk_get(NULL, "emi_slow_clk");
- if (IS_ERR(emi_slow_clk)) {
- printk(KERN_DEBUG "%s: failed to get emi_slow_clk\n",
- __func__);
- return PTR_ERR(emi_slow_clk);
- }
+ ddr_hf_clk = clk_get_parent(ddr_clk);
- nfc_clk = clk_get(NULL, "nfc_clk");
- if (IS_ERR(nfc_clk)) {
- printk(KERN_DEBUG "%s: failed to get nfc_clk\n",
+ if (IS_ERR(ddr_hf_clk)) {
+ printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n",
__func__);
- return PTR_ERR(nfc_clk);
+ return PTR_ERR(ddr_hf_clk);
}
ahb_clk = clk_get(NULL, "ahb_clk");
@@ -389,20 +678,6 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(ahb_clk);
}
- vpu_core_clk = clk_get(NULL, "vpu_core_clk");
- if (IS_ERR(vpu_core_clk)) {
- printk(KERN_DEBUG "%s: failed to get vpu_core_clk\n",
- __func__);
- return PTR_ERR(vpu_core_clk);
- }
-
- ddr_clk = clk_get(NULL, "ddr_clk");
- if (IS_ERR(ddr_clk)) {
- printk(KERN_DEBUG "%s: failed to get ddr_clk\n",
- __func__);
- return PTR_ERR(ddr_clk);
- }
-
cpu_clk = clk_get(NULL, "cpu_clk");
if (IS_ERR(cpu_clk)) {
printk(KERN_DEBUG "%s: failed to get cpu_clk\n",
@@ -410,35 +685,25 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return PTR_ERR(cpu_clk);
}
- ipu_clk = clk_get(NULL, "ipu_clk");
- if (IS_ERR(ipu_clk)) {
- printk(KERN_DEBUG "%s: failed to get ipu_clk\n",
- __func__);
- return PTR_ERR(ipu_clk);
- }
-
if (cpu_is_mx51())
emi_garb_clk = clk_get(NULL, "emi_garb_clk");
- else
+ else if (cpu_is_mx53())
emi_garb_clk = clk_get(NULL, "emi_intr_clk.1");
+ else
+ emi_garb_clk = clk_get(NULL, "ocram_clk");
if (IS_ERR(emi_garb_clk)) {
printk(KERN_DEBUG "%s: failed to get emi_garb_clk\n",
__func__);
return PTR_ERR(emi_garb_clk);
}
- vpu_clk = clk_get(NULL, "vpu_clk");
- if (IS_ERR(vpu_clk)) {
- printk(KERN_DEBUG "%s: failed to get vpu_clk\n",
- __func__);
- return PTR_ERR(vpu_clk);
- }
-
- periph_apm_clk = clk_get(NULL, "periph_apm_clk");
- if (IS_ERR(periph_apm_clk)) {
- printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n",
- __func__);
- return PTR_ERR(periph_apm_clk);
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ periph_apm_clk = clk_get(NULL, "periph_apm_clk");
+ if (IS_ERR(periph_apm_clk)) {
+ printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n",
+ __func__);
+ return PTR_ERR(periph_apm_clk);
+ }
}
lp_apm = clk_get(NULL, "lp_apm");
@@ -467,6 +732,49 @@ static int __devinit busfreq_probe(struct platform_device *pdev)
return err;
}
+ pll1_rate = clk_get_rate(pll1_sw_clk);
+ pll2_rate = clk_get_rate(pll2);
+
+ if (pll2_rate == 665000000) {
+ /* for mx51 */
+ lp_normal_rate = pll2_rate / 5;
+ lp_med_rate = pll2_rate / 8;
+ ddr_normal_rate = pll1_rate / 4; /* 200M */
+ ddr_low_rate = pll1_rate / 6; /* 133M */
+ } else if (pll2_rate == 600000000) {
+ /* for mx53 evk rev.A */
+ lp_normal_rate = pll2_rate / 5;
+ lp_med_rate = pll2_rate / 8;
+ ddr_normal_rate = pll2_rate / 2;
+ ddr_low_rate = pll2_rate / 2;
+ } else if (pll2_rate == 400000000) {
+ /* for mx53 evk rev.B */
+ lp_normal_rate = pll2_rate / 3;
+ lp_med_rate = pll2_rate / 5;
+ if (cpu_is_mx53()) {
+ ddr_normal_rate = pll2_rate / 1;
+ ddr_low_rate = pll2_rate / 3;
+ } else if (cpu_is_mx50()) {
+ ddr_normal_rate = clk_get_rate(ddr_clk);
+ ddr_low_rate = LP_APM_CLK;
+ }
+ }
+ if (cpu_is_mx50()) {
+ iram_alloc(SZ_8K, &iram_paddr);
+ /* Need to remap the area here since we want the memory region
+ to be executable. */
+ ddr_freq_change_iram_base = __arm_ioremap(iram_paddr,
+ SZ_8K, MT_HIGH_VECTORS);
+ memcpy(ddr_freq_change_iram_base, mx50_ddr_freq_change, SZ_8K);
+ change_ddr_freq = (void *)ddr_freq_change_iram_base;
+
+ lp_regulator = regulator_get(NULL, "SW2");
+ if (IS_ERR(lp_regulator)) {
+ printk(KERN_DEBUG
+ "%s: failed to get lp regulator\n", __func__);
+ return PTR_ERR(lp_regulator);
+ }
+ }
cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
low_bus_freq_mode = 0;
high_bus_freq_mode = 1;