#define LPAPM_CLK 24000000
#define DDR_MED_CLK 400000000
#define DDR3_NORMAL_CLK 528000000
+#define AXI_CLK_RATE 270000000
+#define GPC_PGC_GPU_PGCR_OFFSET 0x260
+#define GPC_CNTR_OFFSET 0x0
+
+
DEFINE_SPINLOCK(ddr_freq_lock);
int low_freq_bus_used(void);
void set_ddr_freq(int ddr_freq);
+extern int init_mmdc_settings(void);
extern struct cpu_op *(*get_cpu_op)(int *op);
extern int update_ddr_freq(int ddr_rate);
-
+extern void __iomem *gpc_base;
struct mutex bus_freq_mutex;
static int cpu_op_nr;
static struct cpu_op *cpu_op_tbl;
static struct clk *pll2_400;
+static struct clk *axi_clk;
+static struct clk *periph_clk;
+static struct clk *pll3_540;
static struct clk *cpu_clk;
static unsigned int org_ldo;
static struct clk *pll3;
return;
}
+ /* Set the axi_clk to be sourced from the periph_clk.
+ * So that its frequency can be lowered down to 50MHz
+ * or 24MHz as the case may be. */
+ clk_set_parent(axi_clk, periph_clk);
+
clk_enable(pll3);
if (lp_audio_freq) {
if (cpu_is_mx6q()) {
/* Power gate the PU LDO. */
+ /* Power gate the PU domain first. */
+ /* enable power down request */
+ reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
+ __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
+ /* power down request */
+ reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET);
+ __raw_writel(reg | 0x1, gpc_base + GPC_CNTR_OFFSET);
+ /* Wait for power down to complete. */
+ while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x1)
+ ;
+
org_ldo = reg = __raw_readl(ANADIG_REG_CORE);
reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET);
__raw_writel(reg, ANADIG_REG_CORE);
}
clk_disable(pll3);
mutex_unlock(&bus_freq_mutex);
-
}
/* Set the DDR, AHB to 24MHz.
*/
int set_high_bus_freq(int high_bus_freq)
{
+ unsigned long reg;
+
if (busfreq_suspended)
return 0;
}
clk_enable(pll3);
+ if (clk_get_parent(axi_clk) != pll3_540) {
+ /* We need to set axi_clk to be sourced from PLL3_540MHz. */
+ /* Ensure the divider is set to divide by 2 before changing the
+ * parent. */
+ if (low_bus_freq_mode)
+ clk_set_rate(axi_clk, clk_get_rate(axi_clk) / 2);
+ clk_set_parent(axi_clk, pll3_540);
+ clk_set_rate(axi_clk, AXI_CLK_RATE);
+ }
+
/* Enable the PU LDO */
- if (cpu_is_mx6q() && low_bus_freq_mode)
+ if (cpu_is_mx6q() && low_bus_freq_mode) {
__raw_writel(org_ldo, ANADIG_REG_CORE);
+ /* enable power up request */
+ reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
+ __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
+ /* power up request */
+ reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET);
+ __raw_writel(reg | 0x2, gpc_base + GPC_CNTR_OFFSET);
+ /* Wait for the power up bit to clear */
+ while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x2)
+ ;
+ }
+
if (high_bus_freq) {
update_ddr_freq(ddr_normal_rate);
if (med_bus_freq_mode)
pll2_400 = clk_get(NULL, "pll2_pfd_400M");
if (IS_ERR(pll2_400)) {
- printk(KERN_DEBUG "%s: failed to get axi_clk\n",
+ printk(KERN_DEBUG "%s: failed to get pll2_pfd_400M\n",
__func__);
return PTR_ERR(pll2_400);
}
}
pll3 = clk_get(NULL, "pll3_main_clk");
+ if (IS_ERR(pll3)) {
+ printk(KERN_DEBUG "%s: failed to get pll3\n",
+ __func__);
+ return PTR_ERR(cpu_clk);
+ }
+
+ axi_clk = clk_get(NULL, "axi_clk");
+ if (IS_ERR(axi_clk)) {
+ printk(KERN_DEBUG "%s: failed to get axi_clk\n",
+ __func__);
+ return PTR_ERR(axi_clk);
+ }
+
+ periph_clk = clk_get(NULL, "periph_clk");
+ if (IS_ERR(periph_clk)) {
+ printk(KERN_DEBUG "%s: failed to get periph_clk\n",
+ __func__);
+ return PTR_ERR(periph_clk);
+ }
+
+ pll3_540 = clk_get(NULL, "pll3_pfd_540M");
+ if (IS_ERR(pll3_540)) {
+ printk(KERN_DEBUG "%s: failed to get periph_clk\n",
+ __func__);
+ return PTR_ERR(pll3_540);
+ }
err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
if (err) {
mutex_init(&bus_freq_mutex);
+ init_mmdc_settings();
+
return 0;
}
extern int lp_audio_freq;
void __iomem *apll_base;
+static struct clk ipu1_clk;
+static struct clk ipu2_clk;
+static struct clk axi_clk;
static struct clk pll1_sys_main_clk;
static struct clk pll2_528_bus_main_clk;
static struct clk pll2_pfd_400M;
.round_rate = pfd_round_rate,
};
+static int pfd_540M_set_rate(struct clk *clk, unsigned long rate)
+{
+ if ((clk_get_parent(&ipu1_clk) == clk) ||
+ (clk_get_parent(&ipu2_clk) == clk) ||
+ (clk_get_parent(&axi_clk) == clk))
+ WARN(1, "CHANGING rate of 540M PFD when IPU and \
+ AXI is sourced from it \n");
+
+ return pfd_set_rate(clk, rate);
+}
+
static struct clk pll3_pfd_540M = {
__INIT_CLK_DEBUG(pll3_pfd_540M)
.parent = &pll3_usb_otg_main_clk,
.enable_shift = ANADIG_PFD1_FRAC_OFFSET,
.enable = _clk_pfd_enable,
.disable = _clk_pfd_disable,
- .set_rate = pfd_set_rate,
+ .set_rate = pfd_540M_set_rate,
.get_rate = pfd_get_rate,
.round_rate = pfd_round_rate,
.get_rate = pfd_get_rate,
.set_rate = _clk_vpu_axi_set_rate,
.get_rate = _clk_vpu_axi_get_rate,
.secondary = &vpu_clk[1],
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
},
{
.parent = &mmdc_ch0_axi_clk[0],
.round_rate = _clk_ipu_round_rate,
.set_rate = _clk_ipu1_set_rate,
.get_rate = _clk_ipu1_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static int _clk_ipu2_set_parent(struct clk *clk, struct clk *parent)
.round_rate = _clk_ipu_round_rate,
.set_rate = _clk_ipu2_set_rate,
.get_rate = _clk_ipu2_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static struct clk usdhc_dep_clk = {
.set_rate = _clk_ldb_di0_set_rate,
.round_rate = _clk_ldb_di_round_rate,
.get_rate = _clk_ldb_di0_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
static unsigned long _clk_ldb_di1_get_rate(struct clk *clk)
.set_rate = _clk_ldb_di1_set_rate,
.round_rate = _clk_ldb_di_round_rate,
.get_rate = _clk_ldb_di1_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
};
.set_rate = _clk_ipu1_di0_set_rate,
.round_rate = _clk_ipu_di_round_rate,
.get_rate = _clk_ipu1_di0_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
},
{
__INIT_CLK_DEBUG(ipu1_di_clk_1)
.set_rate = _clk_ipu1_di1_set_rate,
.round_rate = _clk_ipu_di_round_rate,
.get_rate = _clk_ipu1_di1_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
},
};
.set_rate = _clk_ipu2_di0_set_rate,
.round_rate = _clk_ipu_di_round_rate,
.get_rate = _clk_ipu2_di0_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
},
{
__INIT_CLK_DEBUG(ipu2_di_clk_1)
.set_rate = _clk_ipu2_di1_set_rate,
.round_rate = _clk_ipu_di_round_rate,
.get_rate = _clk_ipu2_di1_get_rate,
- .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE,
+ .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE,
},
};
/* on mx6dl gpu2d_axi_clk source from mmdc0 directly */
clk_set_parent(&gpu2d_axi_clk, &mmdc_ch0_axi_clk[0]);
- /* set axi_clk parent to pll3_pfd_540M */
- clk_set_parent(&axi_clk, &pll3_pfd_540M);
+ /* pxp & epdc */
+ clk_set_parent(&ipu2_clk, &pll2_pfd_400M);
+ clk_set_rate(&ipu2_clk, 200000000);
+ } else if (cpu_is_mx6q())
+ /* Donot source IPU from MMDC clock, as it can be scaled. */
+ clk_set_parent(&ipu2_clk, &pll3_pfd_540M);
+
+ /* Donot source IPU from MMDC clock, as it can be scaled. */
+ clk_set_parent(&ipu1_clk, &pll3_pfd_540M);
+
+ /* set axi_clk parent to pll3_pfd_540M, don't source from
+ * periph_clk as it can be scaled.
+ */
+ clk_set_parent(&axi_clk, &pll3_pfd_540M);
+ /* Need to keep PLL3_PFD_540M enabled until AXI is sourced from it. */
+ clk_enable(&axi_clk);
- /* on mx6dl, max ipu clock is 274M */
- clk_set_parent(&ipu1_clk, &pll3_pfd_540M);
- }
if (cpu_is_mx6q())
clk_set_parent(&gpu2d_core_clk[0], &pll3_usb_otg_main_clk);
void *mx6_wait_in_iram_base;
void (*mx6_wait_in_iram)(void);
extern void mx6_wait(void);
-extern int init_mmdc_settings(void);
struct cpu_op *(*get_cpu_op)(int *op);
bool enable_wait_mode;
num_cpu_idle_lock = 0x0;
- init_mmdc_settings();
return 0;
}
postcore_initcall(post_cpu_init);
ldr r0, [r6, #0x14]
and r0, r0, #0x2000000
cmp r0, #0x2000000
- beq switch_pre_periph_clk_528
+ beq set_ahb_podf_before_switch
/* Step 1: Change periph_clk to be sourced from pll3_clk. */
/* Ensure PLL3 is the source and set the divider to 1. */
bic r0, r0, #0x38000000
str r0, [r6, #0x14]
+ /* Set the AHB dividers before the switch. */
+ /* Don't change AXI clock divider. */
+ /* Set the MMDC_DIV=1, AHB_DIV=4 (need to maintain GPT divider). */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x381D00
+ bic r0, r0, r2
+ orr r0, r0, #0xD00
+ str r0, [r6, #0x14]
+
+wait_div_update528:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update528
+
/* Now switch periph_clk to pll3_main_clk. */
ldr r0, [r6, #0x14]
orr r0, r0, #0x2000000
cmp r0, #0
bne periph_clk_switch3
-switch_pre_periph_clk_528:
-
- /* Now switch pre_periph_clk to PLL2_528MHz. */
- ldr r0, [r6, #0x18]
- bic r0, r0, #0xC0000
- str r0, [r6, #0x18]
+ b switch_pre_periph_clk_528
- /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4 (need to maintain GPT divider). */
+set_ahb_podf_before_switch:
+ /* Set the AHB dividers before the switch. */
+ /* Especially if the AHB is at 24MHz, divider
+ * would be at divide by 1 and clock
+ * would be too fast when switching to PLL3.
+ */
+ /* Don't change AXI clock divider. */
+ /* Set the MMDC_DIV=1, AHB_DIV=4 (need to maintain GPT divider). */
ldr r0, [r6, #0x14]
- ldr r2, =0x3F1D00
+ ldr r2, =0x381D00
bic r0, r0, r2
- orr r0, r0, #0x10000
orr r0, r0, #0xD00
str r0, [r6, #0x14]
-wait_div_update1:
+wait_div_update528_1:
ldr r0, [r6, #0x48]
cmp r0, #0
- bne wait_div_update1
+ bne wait_div_update528_1
+
+switch_pre_periph_clk_528:
+
+ /* Now switch pre_periph_clk to PLL2_528MHz. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0xC0000
+ str r0, [r6, #0x18]
/* Now switch periph_clk back. */
ldr r0, [r6, #0x14]
/* Change the GPT divider so that its at 6MHz. */
ldr r0, [r6, #0x1C]
bic r0, r0, #0x3F
- orr r0, r0, #0xB
+ orr r0, r0, #0xA
str r0, [r6, #0x1C]
-
.endm
.macro switch_to_400MHz
/* check if periph_clk_sel is already set */
- ldr r0, [r6, #0x14]
- and r0, r0, #0x2000000
- cmp r0, #0x2000000
- beq switch_pre_periph_clk_400
+ ldr r0, [r6, #0x14]
+ and r0, r0, #0x2000000
+ cmp r0, #0x2000000
+ beq set_ahb_podf_before_switch1
/* Step 1: Change periph_clk to be sourced from pll3_clk. */
/* Ensure PLL3 is the source and set the divider to 1. */
cmp r0, #0
bne periph_clk_switch5
-switch_pre_periph_clk_400:
+ b switch_pre_periph_clk_400
- /* Now switch pre_periph_clk to PFD_400MHz. */
- ldr r0, [r6, #0x18]
- bic r0, r0, #0xC0000
- orr r0, r0, #0x40000
- str r0, [r6, #0x18]
-
- /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=3 (need to maintain GPT divider). */
+set_ahb_podf_before_switch1:
+ /* Set the AHB dividers before the switch. */
+ /* Especially if the AHB is at 24MHz, divider
+ * would be at divide by 1 and clock
+ * would be too fast when switching to PLL3.
+ */
+ /* Don't change AXI clock divider. */
+ /* Set the MMDC_DIV=1, AHB_DIV=4 (need to maintain GPT divider). */
ldr r0, [r6, #0x14]
- ldr r2, =0x3F1D00
+ ldr r2, =0x381D00
bic r0, r0, r2
- orr r0, r0, #0x10000
- orr r0, r0, #0x900
+ orr r0, r0, #0xD00
str r0, [r6, #0x14]
-wait_div_update400:
+wait_div_update400_1:
ldr r0, [r6, #0x48]
cmp r0, #0
- bne wait_div_update400
+ bne wait_div_update400_1
+
+switch_pre_periph_clk_400:
+
+ /* Now switch pre_periph_clk to PFD_400MHz. */
+ ldr r0, [r6, #0x18]
+ bic r0, r0, #0xC0000
+ orr r0, r0, #0x40000
+ str r0, [r6, #0x18]
/* Now switch periph_clk back. */
ldr r0, [r6, #0x14]
cmp r0, #0
bne periph_clk_switch6
+ /* Change AHB divider so that we are at 400/3=133MHz. */
+ /* Don't change AXI clock divider. */
+ /* Set the MMDC_DIV=1, AHB_DIV=3 (need to maintain GPT divider). */
+ ldr r0, [r6, #0x14]
+ ldr r2, =0x381D00
+ bic r0, r0, r2
+ orr r0, r0, #0x900
+ str r0, [r6, #0x14]
+
+wait_div_update400_2:
+ ldr r0, [r6, #0x48]
+ cmp r0, #0
+ bne wait_div_update400_2
+
/* Change the GPT divider so that its at 6MHz. */
ldr r0, [r6, #0x1C]
bic r0, r0, #0x3F
- orr r0, r0, #0xB
+ orr r0, r0, #0xA
str r0, [r6, #0x1C]
.endm
continue_dll_on:
- /* set step-by-step mode */
+ /* set SBS step-by-step mode */
ldr r0, [r5, #0x410]
orr r0, r0, #0x100
str r0, [r5, #0x410]
sub r1, r1, #1
cmp r1, #0
bgt delay5
-
/* Disable dqs pull down in the IOMUX. */
/*
setmem /32 0x020e05a8 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 - DSE=110
/* Set the interrupt to be pending in the GIC. */
reg = 1 << (irq_used[cpu] % 32);
writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + (irq_used[cpu] / 32) * 4);
- udelay(10);
}
}
while (cpus_in_wfe != online_cpus)
memcpy(ddr_freq_change_iram_base, mx6_ddr_freq_change, SZ_8K);
mx6_change_ddr_freq = (void *)ddr_freq_change_iram_base;
+ curr_ddr_rate = ddr_normal_rate;
+
for_each_online_cpu(cpu) {
/* Set up a reserved interrupt to get all the active cores into a WFE state
* before changing the DDR frequency.