From 220079eab544ef16d2bbf2606e56de38d4e4c7c4 Mon Sep 17 00:00:00 2001 From: Terry Lv Date: Mon, 9 Aug 2010 18:13:34 +0800 Subject: ENGR00126079: Add clk command support for mx51 Add clk command support for mx51. Signed-off-by: Terry Lv --- board/freescale/mx51_bbg/lowlevel_init.S | 6 +- board/freescale/mx51_bbg/mx51_bbg.c | 28 +- cpu/arm_cortexa8/mx51/generic.c | 653 ++++++++++++++++++++++++++++++- cpu/arm_cortexa8/mx53/generic.c | 10 +- drivers/misc/imx_iim.c | 4 +- include/asm-arm/arch-mx51/mx51.h | 21 +- include/configs/mx51_bbg.h | 3 + 7 files changed, 693 insertions(+), 32 deletions(-) diff --git a/board/freescale/mx51_bbg/lowlevel_init.S b/board/freescale/mx51_bbg/lowlevel_init.S index f7f780a..8b9d338 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 PLL 2 for UART's, get 66.5MHz from it */ - ldr r1, =0xA5A2A020 + /* Use default for UART clock */ + ldr r1, =0xA6A2A020 str r1, [r0, #CLKCTL_CSCMR1] - ldr r1, =0x00C30321 + ldr r1, =0x00C30318 str r1, [r0, #CLKCTL_CSCDR1] /* make sure divider effective */ diff --git a/board/freescale/mx51_bbg/mx51_bbg.c b/board/freescale/mx51_bbg/mx51_bbg.c index 1f49c0e..30fed3d 100644 --- a/board/freescale/mx51_bbg/mx51_bbg.c +++ b/board/freescale/mx51_bbg/mx51_bbg.c @@ -588,7 +588,7 @@ static void setup_core_voltage_spi(void) pmic_reg(slave, 34, val, 1); /* Write needed to update Charger 0 */ - pmic_reg(slave, 48, 0x0023807F, 1); + pmic_reg(slave, 48, 0x0023807f, 1); /* power up the system first */ pmic_reg(slave, 34, 0x00200000, 1); @@ -596,17 +596,17 @@ static void setup_core_voltage_spi(void) if (is_soc_rev(CHIP_REV_2_0) >= 0) { /* Set core voltage to 1.1V */ val = pmic_reg(slave, 24, 0, 0); - val = (val & (~0x1F)) | 0x14; + val = (val & (~0x1f)) | 0x14; pmic_reg(slave, 24, val, 1); /* Setup VCC (SW2) to 1.25 */ val = pmic_reg(slave, 25, 0, 0); - val = (val & (~0x1F)) | 0x1A; + val = (val & (~0x1f)) | 0x1a; pmic_reg(slave, 25, val, 1); /* Setup 1V2_DIG1 (SW3) to 1.25 */ val = pmic_reg(slave, 26, 0, 0); - val = (val & (~0x1F)) | 0x1A; + val = (val & (~0x1f)) | 0x1a; pmic_reg(slave, 26, val, 1); udelay(50); /* Raise the core frequency to 800MHz */ @@ -615,37 +615,37 @@ static void setup_core_voltage_spi(void) /* TO 3.0 */ /* Setup VCC (SW2) to 1.225 */ val = pmic_reg(slave, 25, 0, 0); - val = (val & (~0x1F)) | 0x19; + val = (val & (~0x1f)) | 0x19; pmic_reg(slave, 25, val, 1); /* Setup 1V2_DIG1 (SW3) to 1.2 */ val = pmic_reg(slave, 26, 0, 0); - val = (val & (~0x1F)) | 0x18; + val = (val & (~0x1f)) | 0x18; pmic_reg(slave, 26, val, 1); } - if (((pmic_reg(slave, 7, 0, 0) & 0x1F) < REV_ATLAS_LITE_2_0) || + if (((pmic_reg(slave, 7, 0, 0) & 0x1f) < REV_ATLAS_LITE_2_0) || (((pmic_reg(slave, 7, 0, 0) >> 9) & 0x3) == 0)) { /* Set switchers in PWM mode for Atlas 2.0 and lower */ /* Setup the switcher mode for SW1 & SW2*/ val = pmic_reg(slave, 28, 0, 0); - val = (val & (~0x3C0F)) | 0x1405; + val = (val & (~0x3c0f)) | 0x1405; pmic_reg(slave, 28, val, 1); /* Setup the switcher mode for SW3 & SW4 */ val = pmic_reg(slave, 29, 0, 0); - val = (val & (~0xF0F)) | 0x505; + val = (val & (~0xf0f)) | 0x505; pmic_reg(slave, 29, val, 1); } else { /* Set switchers in Auto in NORMAL mode & STANDBY mode for Atlas 2.0a */ /* Setup the switcher mode for SW1 & SW2*/ val = pmic_reg(slave, 28, 0, 0); - val = (val & (~0x3C0F)) | 0x2008; + val = (val & (~0x3c0f)) | 0x2008; pmic_reg(slave, 28, val, 1); /* Setup the switcher mode for SW3 & SW4 */ val = pmic_reg(slave, 29, 0, 0); - val = (val & (~0xF0F)) | 0x808; + val = (val & (~0xf0f)) | 0x808; pmic_reg(slave, 29, val, 1); } @@ -657,8 +657,8 @@ static void setup_core_voltage_spi(void) /* Set VVIDEO to 2.775V, VAUDIO to 3V, VSD to 3.15V */ val = pmic_reg(slave, 31, 0, 0); - val &= ~0x1FC; - val |= 0x1F4; + val &= ~0x1fc; + val |= 0x1f4; pmic_reg(slave, 31, val, 1); /* Configure VGEN3 and VCAM regulators to use external PNP */ @@ -675,7 +675,7 @@ static void setup_core_voltage_spi(void) writel(reg, GPIO2_BASE_ADDR + 0x4); /* Reset the ethernet controller over GPIO */ - writel(0x1, IOMUXC_BASE_ADDR + 0x0AC); + writel(0x1, IOMUXC_BASE_ADDR + 0x0ac); /* Enable VGEN3, VCAM, VAUDIO, VVIDEO, VSD regulators */ val = 0x49249; diff --git a/cpu/arm_cortexa8/mx51/generic.c b/cpu/arm_cortexa8/mx51/generic.c index 4706a00..d854988 100644 --- a/cpu/arm_cortexa8/mx51/generic.c +++ b/cpu/arm_cortexa8/mx51/generic.c @@ -26,9 +26,18 @@ #include #include #include +#include #ifdef CONFIG_ARCH_CPU_INIT #include #endif +#ifdef CONFIG_CMD_CLOCK +#include +#endif +#ifdef CONFIG_IMX_ECSPI +#include +#include +#endif +#include #include "crm_regs.h" enum pll_clocks { @@ -43,6 +52,51 @@ PLL2_SW_CLK, PLL3_SW_CLK, }; +#define AHB_CLK_ROOT 133333333 +#define IPG_CLK_ROOT 66666666 +#define IPG_PER_CLK_ROOT 40000000 + +#ifdef CONFIG_CMD_CLOCK +#define SZ_DEC_1M 1000000 +#define PLL_PD_MAX 16 /* Actual pd+1 */ +#define PLL_MFI_MAX 15 +#define PLL_MFI_MIN 5 +#define ARM_DIV_MAX 8 +#define IPG_DIV_MAX 4 +#define AHB_DIV_MAX 8 +#define EMI_DIV_MAX 8 +#define NFC_DIV_MAX 8 + +struct fixed_pll_mfd { + u32 ref_clk_hz; + u32 mfd; +}; + +const struct fixed_pll_mfd fixed_mfd[4] = { + {0, 0}, /* reserved */ + {0, 0}, /* reserved */ + {CONFIG_MX51_HCLK_FREQ, 24 * 16}, /* 384 */ + {0, 0}, /* reserved */ +}; + +struct pll_param { + u32 pd; + u32 mfi; + u32 mfn; + u32 mfd; +}; + +#define PLL_FREQ_MAX(_ref_clk_) \ + (4 * _ref_clk_ * PLL_MFI_MAX) +#define PLL_FREQ_MIN(_ref_clk_) \ + ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX) +#define MAX_DDR_CLK 420000000 +#define AHB_CLK_MAX 133333333 +#define IPG_CLK_MAX (AHB_CLK_MAX / 2) +#define NFC_CLK_MAX 25000000 +#define HSP_CLK_MAX 133333333 +#endif + static u32 __decode_pll(enum pll_clocks pll, u32 infreq) { u32 mfi, mfn, mfd, pd; @@ -85,6 +139,46 @@ static u32 __get_periph_clk(void) return __decode_pll(PLL2_CLK, CONFIG_MX51_HCLK_FREQ); } +static u32 __get_axi_a_clk(void) +{ + u32 cbcdr = __REG(MXC_CCM_CBCDR); + u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_A_PODF_MASK) \ + >> MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; + + return __get_periph_clk() / (pdf + 1); +} + +static u32 __get_axi_b_clk(void) +{ + u32 cbcdr = __REG(MXC_CCM_CBCDR); + u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_B_PODF_MASK) \ + >> MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; + + return __get_periph_clk() / (pdf + 1); +} + +static u32 __get_ahb_clk(void) +{ + u32 cbcdr = __REG(MXC_CCM_CBCDR); + u32 pdf = (cbcdr & MXC_CCM_CBCDR_AHB_PODF_MASK) \ + >> MXC_CCM_CBCDR_AHB_PODF_OFFSET; + + return __get_periph_clk() / (pdf + 1); +} + +static u32 __get_emi_slow_clk(void) +{ + u32 cbcdr = __REG(MXC_CCM_CBCDR); + u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL; + u32 pdf = (cbcdr & MXC_CCM_CBCDR_EMI_PODF_MASK) \ + >> MXC_CCM_CBCDR_EMI_PODF_OFFSET; + + if (emi_clk_sel) + return __get_ahb_clk() / (pdf + 1); + + return __get_periph_clk() / (pdf + 1); +} + static u32 __get_ipg_clk(void) { u32 ahb_podf, ipg_podf; @@ -145,6 +239,33 @@ static u32 __get_uart_clk(void) return freq; } +static u32 __get_ddr_clk(void) +{ + u32 ret_val = 0; + u32 cbcmr = __REG(MXC_CCM_CBCMR); + u32 ddr_clk_sel = (cbcmr & MXC_CCM_CBCMR_DDR_CLK_SEL_MASK) \ + >> MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; + + switch (ddr_clk_sel) { + case 0: + ret_val = __get_axi_a_clk(); + break; + case 1: + ret_val = __get_axi_b_clk(); + break; + case 2: + ret_val = __get_emi_slow_clk(); + break; + case 3: + ret_val = __get_ahb_clk(); + break; + default: + break; + } + + return ret_val; +} + /*! + * This function returns the low power audio clock. + */ @@ -197,14 +318,24 @@ unsigned int mxc_get_clock(enum mxc_clock clk) switch (clk) { case MXC_ARM_CLK: return __get_mcu_main_clk(); + case MXC_PER_CLK: + return __get_periph_clk(); case MXC_AHB_CLK: - break; + return __get_ahb_clk(); case MXC_IPG_CLK: return __get_ipg_clk(); case MXC_IPG_PERCLK: return __get_ipg_per_clk(); case MXC_UART_CLK: return __get_uart_clk(); + case MXC_AXI_A_CLK: + return __get_axi_a_clk(); + case MXC_AXI_B_CLK: + return __get_axi_b_clk(); + case MXC_EMI_SLOW_CLK: + return __get_emi_slow_clk(); + case MXC_DDR_CLK: + return __get_ddr_clk(); case MXC_CSPI_CLK: return __get_cspi_clk(); case MXC_FEC_CLK: @@ -230,7 +361,527 @@ void mxc_dump_clocks(void) printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK)); printf("uart clock : %dHz\n", mxc_get_clock(MXC_UART_CLK)); printf("cspi clock : %dHz\n", mxc_get_clock(MXC_CSPI_CLK)); + printf("axi_a clock : %dHz\n", mxc_get_clock(MXC_AXI_A_CLK)); + printf("axi_b clock : %dHz\n", mxc_get_clock(MXC_AXI_B_CLK)); + printf("emi_slow clock: %dHz\n", mxc_get_clock(MXC_EMI_SLOW_CLK)); + printf("ddr clock : %dHz\n", mxc_get_clock(MXC_DDR_CLK)); + printf("esdhc clock : %dHz\n", mxc_get_clock(MXC_ESDHC_CLK)); +} + +#ifdef CONFIG_CMD_CLOCK + +static int config_ddr_clk(u32 emi_clk); +static int config_core_clk(u32 ref, u32 freq); +static int config_periph_clk(u32 ref, u32 freq); + +/* precondition: m>0 and n>0. Let g=gcd(m,n). */ +static int gcd(int m, int n) +{ + int t; + while (m > 0) { + if (n > m) { + t = m; + m = n; + n = t; + } /* swap */ + m -= n; + } + return n; +} + +#ifdef CONFIG_IMX_ECSPI + +static void adjust_core_voltage(int need_increase) +{ + struct spi_slave *slave; + u32 val; + + slave = spi_pmic_probe(); + + val = pmic_reg(slave, 24, 0, 0); + if (need_increase) { + /* Set core voltage to 1.2V */ + val = (val & (~0x1f)) | 0x18; + } else { + /* Set core voltage to 1.1V */ + val = (val & (~0x1f)) | 0x14; + } + pmic_reg(slave, 24, val, 1); + + val = pmic_reg(slave, 26, 0, 0); + if (need_increase) { + /* Setup 1V2_DIG1 (SW3) to 1.25 */ + val = (val & (~0x1f)) | 0x1a; + } else { + /* Setup 1V2_DIG1 (SW3) to 1.2 */ + val = (val & (~0x1f)) | 0x18; + } + pmic_reg(slave, 26, val, 1); + + spi_pmic_free(slave); } +#endif + +/*! + * This is to calculate various parameters based on reference clock and + * targeted clock based on the equation: + * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1) + * This calculation is based on a fixed MFD value for simplicity. + * + * @param ref reference clock freq in Hz + * @param target targeted clock in Hz + * @param pll pll_param structure. + * + * @return 0 if successful; non-zero otherwise. + */ +static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll) +{ + u64 pd, mfi = 1, mfn, mfd, t1; + u32 n_target = target; + u32 n_ref = ref, i; + + /* + * Make sure targeted freq is in the valid range. + * Otherwise the following calculation might be wrong!!! + */ + if (n_target < PLL_FREQ_MIN(ref) || + n_target > PLL_FREQ_MAX(ref)) { + printf("Targeted peripheral clock should be" + "within [%d - %d]\n", + PLL_FREQ_MIN(ref) / SZ_DEC_1M, + PLL_FREQ_MAX(ref) / SZ_DEC_1M); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) { + if (fixed_mfd[i].ref_clk_hz == ref) { + mfd = fixed_mfd[i].mfd; + break; + } + } + + if (i == ARRAY_SIZE(fixed_mfd)) + return -1; + + /* Use n_target and n_ref to avoid overflow */ + for (pd = 1; pd <= PLL_PD_MAX; pd++) { + t1 = n_target * pd; + do_div(t1, (4 * n_ref)); + mfi = t1; + if (mfi > PLL_MFI_MAX) + return -1; + else if (mfi < 5) + continue; + break; + } + /* Now got pd and mfi already */ + /* + mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref; + */ + t1 = n_target * pd; + do_div(t1, 4); + t1 -= n_ref * mfi; + t1 *= mfd; + do_div(t1, n_ref); + mfn = t1; +#ifdef CMD_CLOCK_DEBUG + printf("%d: ref=%d, target=%d, pd=%d," + "mfi=%d,mfn=%d, mfd=%d\n", + __LINE__, ref, (u32)n_target, + (u32)pd, (u32)mfi, (u32)mfn, + (u32)mfd); +#endif + i = 1; + if (mfn != 0) + i = gcd(mfd, mfn); + pll->pd = (u32)pd; + pll->mfi = (u32)mfi; + do_div(mfn, i); + pll->mfn = (u32)mfn; + do_div(mfd, i); + pll->mfd = (u32)mfd; + + return 0; +} + +int clk_info(u32 clk_type) +{ + switch (clk_type) { + case CPU_CLK: + printf("CPU Clock: %dHz\n", + mxc_get_clock(MXC_ARM_CLK)); + break; + case PERIPH_CLK: + printf("Peripheral Clock: %dHz\n", + mxc_get_clock(MXC_PER_CLK)); + break; + case AHB_CLK: + printf("AHB Clock: %dHz\n", + mxc_get_clock(MXC_AHB_CLK)); + break; + case IPG_CLK: + printf("IPG Clock: %dHz\n", + mxc_get_clock(MXC_IPG_CLK)); + break; + case IPG_PERCLK: + printf("IPG_PER Clock: %dHz\n", + mxc_get_clock(MXC_IPG_PERCLK)); + break; + case UART_CLK: + printf("UART Clock: %dHz\n", + mxc_get_clock(MXC_UART_CLK)); + break; + case CSPI_CLK: + printf("CSPI Clock: %dHz\n", + mxc_get_clock(MXC_CSPI_CLK)); + break; + case DDR_CLK: + printf("DDR Clock: %dHz\n", + mxc_get_clock(MXC_DDR_CLK)); + break; + case ALL_CLK: + printf("cpu clock: %dMHz\n", + mxc_get_clock(MXC_ARM_CLK) / SZ_DEC_1M); + mxc_dump_clocks(); + break; + default: + printf("Unsupported clock type! :(\n"); + } + + return 0; +} + +#define calc_div(target_clk, src_clk, limit) ({ \ + u32 tmp = 0; \ + if ((src_clk % target_clk) <= 100) \ + tmp = src_clk / target_clk; \ + else \ + tmp = (src_clk / target_clk) + 1; \ + if (tmp > limit) \ + tmp = limit; \ + (tmp - 1); \ + }) + +static u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) +{ + u32 cbcdr = __REG(MXC_CCM_CBCDR); + u32 tmp_clk = 0, div = 0, clk_sel = 0; + + cbcdr &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + + /* emi_slow_podf divider */ + tmp_clk = __get_emi_slow_clk(); + clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL; + if (clk_sel) { + div = calc_div(tmp_clk, per_clk, 8); + cbcdr &= ~MXC_CCM_CBCDR_EMI_PODF_MASK; + cbcdr |= (div << MXC_CCM_CBCDR_EMI_PODF_OFFSET); + } + + /* axi_b_podf divider */ + tmp_clk = __get_axi_b_clk(); + div = calc_div(tmp_clk, per_clk, 8); + cbcdr &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK; + cbcdr |= (div << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET); + + /* axi_b_podf divider */ + tmp_clk = __get_axi_a_clk(); + div = calc_div(tmp_clk, per_clk, 8); + cbcdr &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK; + cbcdr |= (div << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET); + + /* ahb podf divider */ + tmp_clk = AHB_CLK_ROOT; + div = calc_div(tmp_clk, per_clk, 8); + cbcdr &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + cbcdr |= (div << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + + return cbcdr; +} + +#define CHANGE_PLL_SETTINGS(base, pd, mfi, mfn, mfd) \ + { \ + writel(0x1232, base + PLL_DP_CTL); \ + writel(0x2, base + PLL_DP_CONFIG); \ + writel(((pd - 1) << 0) | (mfi << 4), \ + base + PLL_DP_OP); \ + writel(mfn, base + PLL_DP_MFN); \ + writel(mfd - 1, base + PLL_DP_MFD); \ + writel(((pd - 1) << 0) | (mfi << 4), \ + base + PLL_DP_HFS_OP); \ + writel(mfn, base + PLL_DP_HFS_MFN); \ + writel(mfd - 1, base + PLL_DP_HFS_MFD); \ + writel(0x1232, base + PLL_DP_CTL); \ + while (!readl(base + PLL_DP_CTL) & 0x1) \ + ; \ + } + +static int config_pll_clk(enum pll_clocks pll, struct pll_param *pll_param) +{ + u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR); + u32 pll_base = pll; + u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR); + + switch (pll) { + case PLL1_CLK: + if (((cbcdr >> 30) & 0x1) == 0x1) { + /* Disable IPU and HSC dividers */ + writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); + /* Switch DDR to different source */ + writel(cbcdr & ~0x40000000, + CCM_BASE_ADDR + CLKCTL_CBCDR); + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) + ; + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + } + /* Switch ARM to step clock */ + writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR); + + CHANGE_PLL_SETTINGS(pll_base, pll_param->pd, + pll_param->mfi, pll_param->mfn, + pll_param->mfd); + /* Switch back */ + writel(ccsr & ~0x4, CCM_BASE_ADDR + CLKCTL_CCSR); + + if (((cbcdr >> 30) & 0x1) == 0x1) { + /* Disable IPU and HSC dividers */ + writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); + /* Switch DDR back to PLL1 */ + writel(cbcdr | 0x40000000, + CCM_BASE_ADDR + CLKCTL_CBCDR); + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) + ; + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + config_ddr_clk(200); + } + break; + case PLL2_CLK: + /* Switch to pll2 bypass clock */ + writel(ccsr | 0x2, CCM_BASE_ADDR + CLKCTL_CCSR); + CHANGE_PLL_SETTINGS(pll_base, pll_param->pd, + pll_param->mfi, pll_param->mfn, + pll_param->mfd); + /* Switch back */ + writel(ccsr & ~0x2, CCM_BASE_ADDR + CLKCTL_CCSR); + break; + case PLL3_CLK: + /* Switch to pll3 bypass clock */ + writel(ccsr | 0x1, CCM_BASE_ADDR + CLKCTL_CCSR); + CHANGE_PLL_SETTINGS(pll_base, pll_param->pd, + pll_param->mfi, pll_param->mfn, + pll_param->mfd); + /* Switch back */ + writel(ccsr & ~0x1, CCM_BASE_ADDR + CLKCTL_CCSR); + break; + default: + return -1; + } + + return 0; +} + +static int config_core_clk(u32 ref, u32 freq) +{ + int ret = 0; + u32 pll = 0; + struct pll_param pll_param; + + memset(&pll_param, 0, sizeof(struct pll_param)); + + /* The case that periph uses PLL1 is not considered here */ + pll = freq; + ret = calc_pll_params(ref, pll, &pll_param); + if (ret != 0) { + printf("Can't find pll parameters: %d\n", + ret); + return ret; + } + + return config_pll_clk(PLL1_CLK, &pll_param); +} + +static int config_periph_clk(u32 ref, u32 freq) +{ + int ret = 0; + u32 pll = freq; + struct pll_param pll_param; + + memset(&pll_param, 0, sizeof(struct pll_param)); + + if (__REG(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) { + /* Actually this case is not considered here */ + ret = calc_pll_params(ref, pll, &pll_param); + if (ret != 0) { + printf("Can't find pll parameters: %d\n", + ret); + return ret; + } + switch ((__REG(MXC_CCM_CBCMR) & \ + MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >> + MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) { + case 0: + return config_pll_clk(PLL1_CLK, &pll_param); + break; + case 1: + return config_pll_clk(PLL3_CLK, &pll_param); + break; + case 2: + printf("This clock source can't be changed!\n"); + return -1; + default: + return -1; + } + } else { + u32 old_cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR); + u32 new_cbcdr = calc_per_cbcdr_val(pll, old_cbcmr); + + /* Switch peripheral to PLL3 */ + /* Disable IPU and HSC dividers */ + writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); + writel(0x000010C0, CCM_BASE_ADDR + CLKCTL_CBCMR); + writel(0x13239145, CCM_BASE_ADDR + CLKCTL_CBCDR); + + /* Make sure change is effective */ + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) + ; + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + + /* Setup PLL2 */ + ret = calc_pll_params(ref, pll, &pll_param); + if (ret != 0) { + printf("Can't find pll parameters: %d\n", + ret); + return ret; + } + config_pll_clk(PLL2_CLK, &pll_param); + + /* Switch peripheral back */ + /* Disable IPU and HSC dividers */ + writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); + writel(new_cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR); + writel(old_cbcmr, CCM_BASE_ADDR + CLKCTL_CBCMR); + + /* Make sure change is effective */ + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) + ; + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + puts("\n"); + } + + return 0; +} + +static int config_ddr_clk(u32 emi_clk) +{ + u32 clk_src; + s32 shift = 0, clk_sel, div = 1; + u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR); + u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR); + + if (emi_clk > MAX_DDR_CLK) { + printf("DDR clock should be less than" + "%d MHz, assuming max value \n", + (MAX_DDR_CLK / SZ_DEC_1M)); + emi_clk = MAX_DDR_CLK; + } + + if (((cbcdr >> 30) & 0x1) == 0x1) { + clk_src = __decode_pll(PLL1_CLK, CONFIG_MX51_HCLK_FREQ); + shift = 27; + } else { + clk_src = __get_periph_clk(); + /* Find DDR clock input */ + clk_sel = (cbcmr >> 10) & 0x3; + switch (clk_sel) { + case 0: + shift = 16; + break; + case 1: + shift = 19; + break; + case 2: + shift = 22; + break; + case 3: + shift = 10; + break; + default: + return -1; + } + } + + if ((clk_src % emi_clk) == 0) + div = clk_src / emi_clk; + else + div = (clk_src / emi_clk) + 1; + if (div > 8) + div = 8; + + cbcdr = cbcdr & ~(0x7 << shift); + cbcdr |= ((div - 1) << shift); + /* Disable IPU and HSC dividers */ + writel(0x60000, CCM_BASE_ADDR + CLKCTL_CCDR); + writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR); + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0) + ; + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR); + + return 0; +} + +/*! + * This function assumes the expected core clock has to be changed by + * modifying the PLL. This is NOT true always but for most of the times, + * it is. So it assumes the PLL output freq is the same as the expected + * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN. + * In the latter case, it will try to increase the presc value until + * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to + * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based + * on the targeted PLL and reference input clock to the PLL. Lastly, + * it sets the register based on these values along with the dividers. + * Note 1) There is no value checking for the passed-in divider values + * so the caller has to make sure those values are sensible. + * 2) Also adjust the NFC divider such that the NFC clock doesn't + * exceed NFC_CLK_MAX. + * 3) IPU HSP clock is independent of AHB clock. Even it can go up to + * 177MHz for higher voltage, this function fixes the max to 133MHz. + * 4) This function should not have allowed diag_printf() calls since + * the serial driver has been stoped. But leave then here to allow + * easy debugging by NOT calling the cyg_hal_plf_serial_stop(). + * + * @param ref pll input reference clock (24MHz) + * @param freq core clock in Hz + * @param clk_type clock type, e.g CPU_CLK, DDR_CLK, etc. + * @return 0 if successful; non-zero otherwise + */ +int clk_config(u32 ref, u32 freq, u32 clk_type) +{ + freq *= SZ_DEC_1M; + + switch (clk_type) { + case CPU_CLK: + if (freq > 800) + adjust_core_voltage(1); + else + adjust_core_voltage(0); + if (config_core_clk(ref, freq)) + return -1; + break; + case PERIPH_CLK: + if (config_periph_clk(ref, freq)) + return -1; + break; + case DDR_CLK: + if (config_ddr_clk(freq)) + return -1; + break; + default: + printf("Unsupported or invalid clock type! :(\n"); + } + + return 0; +} +#endif #if defined(CONFIG_DISPLAY_CPUINFO) int print_cpuinfo(void) diff --git a/cpu/arm_cortexa8/mx53/generic.c b/cpu/arm_cortexa8/mx53/generic.c index 664412c..d725bde 100644 --- a/cpu/arm_cortexa8/mx53/generic.c +++ b/cpu/arm_cortexa8/mx53/generic.c @@ -665,7 +665,7 @@ int clk_info(u32 clk_type) (tmp - 1); \ }) -u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) +static u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) { u32 cbcdr = __REG(MXC_CCM_CBCDR); u32 tmp_clk = 0, div = 0, clk_sel = 0; @@ -719,7 +719,7 @@ u32 calc_per_cbcdr_val(u32 per_clk, u32 cbcmr) ; \ } -int config_pll_clk(enum pll_clocks pll, struct pll_param *pll_param) +static int config_pll_clk(enum pll_clocks pll, struct pll_param *pll_param) { u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR); u32 pll_base = pll; @@ -768,7 +768,7 @@ int config_pll_clk(enum pll_clocks pll, struct pll_param *pll_param) return 0; } -int config_core_clk(u32 ref, u32 freq) +static int config_core_clk(u32 ref, u32 freq) { int ret = 0; u32 pll = 0; @@ -788,7 +788,7 @@ int config_core_clk(u32 ref, u32 freq) return config_pll_clk(PLL1_CLK, &pll_param); } -int config_periph_clk(u32 ref, u32 freq) +static int config_periph_clk(u32 ref, u32 freq) { int ret = 0; u32 pll = freq; @@ -850,7 +850,7 @@ int config_periph_clk(u32 ref, u32 freq) return 0; } -int config_ddr_clk(u32 emi_clk) +static int config_ddr_clk(u32 emi_clk) { u32 clk_src; s32 shift = 0, clk_sel, div = 1; diff --git a/drivers/misc/imx_iim.c b/drivers/misc/imx_iim.c index 4bbd4ca..a720791 100644 --- a/drivers/misc/imx_iim.c +++ b/drivers/misc/imx_iim.c @@ -37,6 +37,7 @@ static const struct iim_regs *imx_iim = (struct iim_regs *)IMX_IIM_BASE; +/* static void quick_itoa(u32 num, char *a) { int i, j, k; @@ -46,6 +47,7 @@ static void quick_itoa(u32 num, char *a) a[i] = j + k; } } +*/ /* slen - streng length, e.g.: 23 -> slen=2; abcd -> slen=4 */ /* only convert hex value as string input. so "12" is 0x12. */ @@ -146,7 +148,7 @@ static u32 sense_fuse(s32 bank, s32 row, s32 bit) printf("%s(bank: %d, row: %d, bit: %d failed\n", __func__, bank, row, bit); } - reg_addr = &(imx_iim->sdat); + reg_addr = (s32)&(imx_iim->sdat); return readl(reg_addr); } diff --git a/include/asm-arm/arch-mx51/mx51.h b/include/asm-arm/arch-mx51/mx51.h index 5fc57bb..11aba01 100644 --- a/include/asm-arm/arch-mx51/mx51.h +++ b/include/asm-arm/arch-mx51/mx51.h @@ -448,14 +448,19 @@ enum boot_device { }; enum mxc_clock { -MXC_ARM_CLK = 0, -MXC_AHB_CLK, -MXC_IPG_CLK, -MXC_IPG_PERCLK, -MXC_UART_CLK, -MXC_CSPI_CLK, -MXC_FEC_CLK, -MXC_ESDHC_CLK, + MXC_ARM_CLK = 0, + MXC_PER_CLK, + MXC_AHB_CLK, + MXC_IPG_CLK, + MXC_IPG_PERCLK, + MXC_UART_CLK, + MXC_CSPI_CLK, + MXC_FEC_CLK, + MXC_ESDHC_CLK, + MXC_AXI_A_CLK, + MXC_AXI_B_CLK, + MXC_EMI_SLOW_CLK, + MXC_DDR_CLK }; /* diff --git a/include/configs/mx51_bbg.h b/include/configs/mx51_bbg.h index c240ada..99fd4ac 100644 --- a/include/configs/mx51_bbg.h +++ b/include/configs/mx51_bbg.h @@ -97,6 +97,9 @@ #define CONFIG_CMD_IIM #define CONFIG_CMD_I2C +#define CONFIG_CMD_CLOCK +#define CONFIG_REF_CLK_FREQ CONFIG_MX51_HCLK_FREQ + /* * FUSE Configs * */ -- cgit v1.1