/*!
* This function returns the low power audio clock.
*/
u32 get_lp_apm(void)
{
u32 ret_val = 0;
u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
if (((ccsr >> 10) & 1) == 0) {
ret_val = FREQ_24MHZ;
} else {
ret_val = pll_clock(PLL4);
}
return ret_val;
}
/*!
* This function returns the periph_clk.
*/
u32 get_periph_clk(void)
{
u32 ret_val = 0, clk_sel;
u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
if (((cbcdr >> 25) & 1) == 0) {
ret_val = pll_clock(PLL2);
} else {
clk_sel = (cbcmr >> 12) & 3;
if (clk_sel == 0) {
ret_val = pll_clock(PLL1);
} else if (clk_sel == 1) {
ret_val = pll_clock(PLL3);
} else if (clk_sel == 2) {
ret_val = get_lp_apm();
}
}
return ret_val;
}
/*!
* This function returns the PLL output value in Hz based on pll.
*/
u32 pll_clock(enum plls pll)
{
u64 mfi, mfn, mfd, pdf, ref_clk, pll_out, sign;
u64 dp_ctrl, dp_op, dp_mfd, dp_mfn, clk_sel;
u8 dbl = 0;
dp_ctrl = pll_base[pll][PLL_DP_CTL >> 2];
clk_sel = MXC_GET_FIELD(dp_ctrl, 2, 8);
ref_clk = fixed_mfd[clk_sel].ref_clk_hz;
if ((pll_base[pll][PLL_DP_CTL >> 2] & 0x80) == 0) {
dp_op = pll_base[pll][PLL_DP_OP >> 2];
dp_mfd = pll_base[pll][PLL_DP_MFD >> 2];
dp_mfn = pll_base[pll][PLL_DP_MFN >> 2];
} else {
dp_op = pll_base[pll][PLL_DP_HFS_OP >> 2];
dp_mfd = pll_base[pll][PLL_DP_HFS_MFD >> 2];
dp_mfn = pll_base[pll][PLL_DP_HFS_MFN >> 2];
}
pdf = dp_op & 0xF;
mfi = (dp_op >> 4) & 0xF;
mfi = (mfi <= 5) ? 5 : mfi;
mfd = dp_mfd & 0x07FFFFFF;
mfn = dp_mfn & 0x07FFFFFF;
sign = (mfn < 0x4000000) ? 0 : 1;
mfn = (mfn <= 0x4000000) ? mfn : (0x8000000 - mfn);
dbl = ((dp_ctrl >> 12) & 0x1) + 1;
dbl = dbl * 2;
if (sign == 0) {
pll_out = (dbl * ref_clk * mfi + ((dbl * ref_clk * mfn) / (mfd + 1))) / (pdf + 1);
} else {
pll_out = (dbl * ref_clk * mfi - ((dbl * ref_clk * mfn) / (mfd + 1))) / (pdf + 1);
}
return (u32) pll_out;
}
/*!
* This function returns the emi_core_clk_root clock.
*/
u32 get_emi_core_clk(void)
{
u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
u32 clk_sel = 0, max_pdf = 0, peri_clk = 0, ahb_clk = 0;
u32 ret_val = 0;
max_pdf = (cbcdr >> 10) & 0x7;
peri_clk = get_periph_clk();
ahb_clk = peri_clk / (max_pdf + 1);
clk_sel = (cbcdr >> 26) & 1;
if (clk_sel == 0) {
ret_val = peri_clk;
} else {
ret_val = ahb_clk;
}
return ret_val;
}
/*!
* This function returns the main clock value in Hz.
*/
u32 get_main_clock(enum main_clocks clk)
{
u32 pdf, max_pdf, ipg_pdf, nfc_pdf, clk_sel;
u32 pll, ret_val = 0;
u32 cacrr = readl(CCM_BASE_ADDR + CLKCTL_CACRR);
u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
switch (clk) {
case CPU_CLK:
pdf = cacrr & 0x7;
pll = pll_clock(PLL1);
ret_val = pll / (pdf + 1);
break;
case AHB_CLK:
max_pdf = (cbcdr >> 10) & 0x7;
pll = get_periph_clk();
ret_val = pll / (max_pdf + 1);
break;
case IPG_CLK:
max_pdf = (cbcdr >> 10) & 0x7;
ipg_pdf = (cbcdr >> 8) & 0x3;
pll = get_periph_clk();
ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
break;
case IPG_PER_CLK:
clk_sel = cbcmr & 1;
if (clk_sel == 0) {
clk_sel = (cbcmr >> 1) & 1;
pdf = (((cbcdr >> 6) & 3) + 1) * (((cbcdr >> 3) & 7) + 1) * ((cbcdr & 7) + 1);
if (clk_sel == 0) {
ret_val = get_periph_clk() / pdf;
} else {
ret_val = get_lp_apm() / pdf;
}
} else {
/* Same as IPG_CLK */
max_pdf = (cbcdr >> 10) & 0x7;
ipg_pdf = (cbcdr >> 8) & 0x3;
pll = get_periph_clk();
ret_val = pll / ((max_pdf + 1) * (ipg_pdf + 1));
}
break;
case DDR_CLK:
clk_sel = (cbcmr >> 10) & 3;
pll = get_periph_clk();
if (clk_sel == 0) {
/* AXI A */
pdf = (cbcdr >> 16) & 0x7;
} else if (clk_sel == 1) {
/* AXI B */
pdf = (cbcdr >> 19) & 0x7;
} else if (clk_sel == 2) {
/* EMI SLOW CLOCK ROOT */
pll = get_emi_core_clk();
pdf = (cbcdr >> 22) & 0x7;
} else if (clk_sel == 3) {
/* AHB CLOCK */
pdf = (cbcdr >> 10) & 0x7;
}
ret_val = pll / (pdf + 1);
break;
case NFC_CLK:
pdf = (cbcdr >> 22) & 0x7;
nfc_pdf = (cbcdr >> 13) & 0x7;
pll = get_emi_core_clk();
ret_val = pll / ((pdf + 1) * (nfc_pdf + 1));
break;
case USB_CLK:
clk_sel = (cscmr1 >> 22) & 3;
if (clk_sel == 0) {
pll = pll_clock(PLL1);
} else if (clk_sel == 1) {
pll = pll_clock(PLL2);
} else if (clk_sel == 2) {
pll = pll_clock(PLL3);
} else if (clk_sel == 3) {
pll = get_lp_apm();
}
pdf = (cscdr1 >> 8) & 0x7;
max_pdf = (cscdr1 >> 6) & 0x3;
ret_val = pll / ((pdf + 1) * (max_pdf + 1));
break;
case VPU_CLK:
clk_sel = (cbcmr >> 14) & 3;
pll = get_periph_clk();
if (clk_sel == 0) {
/* AXI A */
pdf = (cbcdr >> 16) & 0x7;
} else if (clk_sel == 1) {
/* AXI B */
pdf = (cbcdr >> 19) & 0x7;
} else if (clk_sel == 2) {
/* EMI SLOW CLOCK ROOT */
pll = get_emi_core_clk();
pdf = (cbcdr >> 22) & 0x7;
} else if (clk_sel == 3) {
/* AHB CLOCK */
pdf = (cbcdr >> 10) & 0x7;
}
ret_val = pll / (pdf + 1);
break;
default:
printf("Unknown clock: %d\n", clk);
break;
}
return ret_val;
}
/*!
* This function returns the peripheral clock value in Hz.
*/
u32 get_peri_clock(enum peri_clocks clk)
{
u32 ret_val = 0, pdf, pre_pdf, clk_sel;
u32 cscmr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCMR1);
u32 cscdr1 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR1);
u32 cscdr2 = readl(CCM_BASE_ADDR + CLKCTL_CSCDR2);
u32 cs1cdr = readl(CCM_BASE_ADDR + CLKCTL_CS1CDR);
u32 cs2cdr = readl(CCM_BASE_ADDR + CLKCTL_CS2CDR);
switch (clk) {
case UART1_BAUD:
case UART2_BAUD:
case UART3_BAUD:
pre_pdf = (cscdr1 >> 3) & 0x7;
pdf = cscdr1 & 0x7;
clk_sel = (cscmr1 >> 24) & 3;
if (clk_sel == 0) {
ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 1) {
ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 2) {
ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
} else {
ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
}
break;
case SSI1_BAUD:
pre_pdf = (cs1cdr >> 6) & 0x7;
pdf = cs1cdr & 0x3F;
clk_sel = (cscmr1 >> 14) & 3;
if (clk_sel == 0) {
ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 0x1) {
ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 0x2) {
ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
} else {
ret_val = CKIH / ((pre_pdf + 1) * (pdf + 1));
}
break;
case SSI2_BAUD:
pre_pdf = (cs2cdr >> 6) & 0x7;
pdf = cs2cdr & 0x3F;
clk_sel = (cscmr1 >> 12) & 3;
if (clk_sel == 0) {
ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 0x1) {
ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 0x2) {
ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
} else {
ret_val = CKIH / ((pre_pdf + 1) * (pdf + 1));
}
break;
case SPI1_CLK:
case SPI2_CLK:
pre_pdf = (cscdr2 >> 25) & 0x7;
pdf = (cscdr2 >> 19) & 0x3F;
clk_sel = (cscmr1 >> 4) & 3;
if (clk_sel == 0) {
ret_val = pll_clock(PLL1) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 1) {
ret_val = pll_clock(PLL2) / ((pre_pdf + 1) * (pdf + 1));
} else if (clk_sel == 2) {
ret_val = pll_clock(PLL3) / ((pre_pdf + 1) * (pdf + 1));
} else {
ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
}
break;
default:
printf("%s(): This clock: %d not supported yet \n", __FUNCTION__, clk);
break;
}
return ret_val;
}
/*!
* Retrieve the freq info based on the passed in module_base.
* @param module_base the base address of the module
* @return frequency in hz (0 means not a valid module)
*/
u32 get_freq(u32 module_base)
{
if (module_base == 0) // as ARM Core doesn't have a module base per se, it is set to 0
return get_main_clock(CPU_CLK);
else if (module_base == ESDCTL_REGISTERS_BASE_ADDR)
return get_main_clock(DDR_CLK);
else if (module_base == UART1_BASE_ADDR)
return get_peri_clock(UART1_BAUD);
else if (module_base == UART3_BASE_ADDR)
return get_peri_clock(UART3_BAUD);
else {
printf("Not a valid module base \n");
return 0;
}
}