1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> 4 */ 5 6 #include <common.h> 7 #include <div64.h> 8 #include <asm/arch/cpu.h> 9 #include <asm/arch/clk.h> 10 #include <asm/io.h> 11 12 static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; 13 14 unsigned int get_sys_clk_rate(void) 15 { 16 if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397) 17 return RTC_CLK_FREQUENCY * 397; 18 else 19 return OSC_CLK_FREQUENCY; 20 } 21 22 unsigned int get_hclk_pll_rate(void) 23 { 24 unsigned long long fin, fref, fcco, fout; 25 u32 val, m_div, n_div, p_div; 26 27 /* 28 * Valid frequency ranges: 29 * 1 * 10^6 <= Fin <= 20 * 10^6 30 * 1 * 10^6 <= Fref <= 27 * 10^6 31 * 156 * 10^6 <= Fcco <= 320 * 10^6 32 */ 33 34 fref = fin = get_sys_clk_rate(); 35 if (fin > 20000000ULL || fin < 1000000ULL) 36 return 0; 37 38 val = readl(&clk->hclkpll_ctrl); 39 m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1; 40 n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1; 41 if (val & CLK_HCLK_PLL_DIRECT) 42 p_div = 0; 43 else 44 p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1; 45 p_div = 1 << p_div; 46 47 if (val & CLK_HCLK_PLL_BYPASS) { 48 do_div(fin, p_div); 49 return fin; 50 } 51 52 do_div(fref, n_div); 53 if (fref > 27000000ULL || fref < 1000000ULL) 54 return 0; 55 56 fcco = fref * m_div; 57 fout = fcco; 58 if (val & CLK_HCLK_PLL_FEEDBACK) 59 fcco *= p_div; 60 else 61 do_div(fout, p_div); 62 63 if (fcco > 320000000ULL || fcco < 156000000ULL) 64 return 0; 65 66 return fout; 67 } 68 69 unsigned int get_hclk_clk_div(void) 70 { 71 u32 val; 72 73 val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK; 74 75 return 1 << val; 76 } 77 78 unsigned int get_hclk_clk_rate(void) 79 { 80 return get_hclk_pll_rate() / get_hclk_clk_div(); 81 } 82 83 unsigned int get_periph_clk_div(void) 84 { 85 u32 val; 86 87 val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK; 88 89 return (val >> 2) + 1; 90 } 91 92 unsigned int get_periph_clk_rate(void) 93 { 94 if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) 95 return get_sys_clk_rate(); 96 97 return get_hclk_pll_rate() / get_periph_clk_div(); 98 } 99 100 unsigned int get_sdram_clk_rate(void) 101 { 102 unsigned int src_clk; 103 104 if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) 105 return get_sys_clk_rate(); 106 107 src_clk = get_hclk_pll_rate(); 108 109 if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) { 110 /* using DDR */ 111 switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) { 112 case CLK_HCLK_DDRAM_HALF: 113 return src_clk/2; 114 case CLK_HCLK_DDRAM_NOMINAL: 115 return src_clk; 116 default: 117 return 0; 118 } 119 } else { 120 /* using SDR */ 121 switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) { 122 case CLK_HCLK_ARM_PLL_DIV_4: 123 return src_clk/4; 124 case CLK_HCLK_ARM_PLL_DIV_2: 125 return src_clk/2; 126 case CLK_HCLK_ARM_PLL_DIV_1: 127 return src_clk; 128 default: 129 return 0; 130 } 131 } 132 } 133 134 int get_serial_clock(void) 135 { 136 return get_periph_clk_rate(); 137 } 138