diff options
-rw-r--r-- | board/freescale/mx51_bbg/lowlevel_init.S | 6 | ||||
-rw-r--r-- | cpu/arm_cortexa8/mx51/generic.c | 69 |
2 files changed, 72 insertions, 3 deletions
diff --git a/board/freescale/mx51_bbg/lowlevel_init.S b/board/freescale/mx51_bbg/lowlevel_init.S index 8b9d338..f7f780a 100644 --- a/board/freescale/mx51_bbg/lowlevel_init.S +++ b/board/freescale/mx51_bbg/lowlevel_init.S @@ -242,10 +242,10 @@ str r1, [r0, #CLKCTL_CCGR5] str r1, [r0, #CLKCTL_CCGR6] - /* Use default for UART clock */ - ldr r1, =0xA6A2A020 + /* Use PLL 2 for UART's, get 66.5MHz from it */ + ldr r1, =0xA5A2A020 str r1, [r0, #CLKCTL_CSCMR1] - ldr r1, =0x00C30318 + ldr r1, =0x00C30321 str r1, [r0, #CLKCTL_CSCDR1] /* make sure divider effective */ diff --git a/cpu/arm_cortexa8/mx51/generic.c b/cpu/arm_cortexa8/mx51/generic.c index d02bc5f..c26f8ea 100644 --- a/cpu/arm_cortexa8/mx51/generic.c +++ b/cpu/arm_cortexa8/mx51/generic.c @@ -562,6 +562,28 @@ int clk_info(u32 clk_type) (tmp - 1); \ }) +#define calc_pred_n_podf(target_clk, src_clk, p_pred, p_podf, pred_limit, podf_limit) { \ + u32 div = calc_div(target_clk, src_clk, \ + pred_limit * podf_limit); \ + u32 tmp = 0, tmp_i = 0, tmp_j = 0; \ + if (div > (pred_limit * podf_limit)) {\ + tmp_i = pred_limit; \ + tmp_j = podf_limit; \ + } \ + for (tmp_i = 1; tmp_i <= pred_limit; ++tmp_i) { \ + for (tmp_j = 1; tmp_j <= podf_limit; ++tmp_j) { \ + if (div == (tmp_i * tmp_j)) { \ + tmp = 1; \ + break; \ + } \ + } \ + if (1 == tmp) \ + break; \ + } \ + *p_pred = tmp_j - 1; \ + *p_podf = tmp_i - 1; \ + } + static u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) { u32 cbcdr = __REG(MXC_CCM_CBCDR); @@ -599,6 +621,29 @@ static u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) return cbcdr; } +static u32 calc_per_cscdr1_val(u32 per_clk) +{ + u32 cscdr1 = __REG(MXC_CCM_CSCDR1); + u32 tmp_clk = 0, pred, podf; + + /* + * Currently, most clocks in scsmr1 will use pll3 as clock source, + * except uart. + * So we will just adjust uart clock here. + */ + tmp_clk = __get_uart_clk(); + calc_pred_n_podf(tmp_clk, per_clk, &pred, &podf, 8, 8); + + cscdr1 &= + !(MXC_CCM_CSCDR1_UART_CLK_PRED_MASK + | MXC_CCM_CSCDR1_UART_CLK_PODF_MASK); + + cscdr1 |= (pred << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET); + cscdr1 |= (podf << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + + return cscdr1; +} + #define CHANGE_PLL_SETTINGS(base, pd, mfi, mfn, mfd) \ { \ writel(0x1232, base + PLL_DP_CTL); \ @@ -732,8 +777,21 @@ static int config_periph_clk(u32 ref, u32 freq) return -1; } } else { + u32 pll3_freq = __decode_pll(PLL3_CLK, CONFIG_MX51_HCLK_FREQ); + u32 old_pll2_freq = + __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ); u32 old_cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR); u32 new_cbcdr = calc_per_cbcdr_val(pll, old_cbcmr); + u32 new_cscdr1 = calc_per_cscdr1_val(pll); + + /* Set PLL3 to PLL2 freq */ + ret = calc_pll_params(ref, old_pll2_freq, &pll_param); + if (ret != 0) { + printf("Can't find pll parameters: %d\n", + ret); + return ret; + } + config_pll_clk(PLL3_CLK, &pll_param); /* Switch peripheral to PLL3 */ /* Disable IPU and HSC dividers */ @@ -760,11 +818,22 @@ static int config_periph_clk(u32 ref, u32 freq) writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); writel(new_cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR); writel(old_cbcmr, CCM_BASE_ADDR + CLKCTL_CBCMR); + writel(new_cscdr1, CCM_BASE_ADDR + CLKCTL_CSCDR1); + + /* Switch PLL3's freq back */ + ret = calc_pll_params(ref, pll3_freq, &pll_param); + if (ret != 0) { + printf("Can't find pll parameters: %d\n", + ret); + return ret; + } + config_pll_clk(PLL3_CLK, &pll_param); /* Make sure change is effective */ while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) ; writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + puts("\n"); } |