imx53 计算各个模块的时钟函数

/*!

 * 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;

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值