1 /* 2 * Copyright (C) 2009 Samsung Electronics 3 * Minkyu Kang <mk7.kang@samsung.com> 4 * Heungjun Kim <riverful.kim@samsung.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <asm/io.h> 11 #include <asm/arch/clock.h> 12 #include <asm/arch/clk.h> 13 14 #define CLK_M 0 15 #define CLK_D 1 16 #define CLK_P 2 17 18 #ifndef CONFIG_SYS_CLK_FREQ_C100 19 #define CONFIG_SYS_CLK_FREQ_C100 12000000 20 #endif 21 #ifndef CONFIG_SYS_CLK_FREQ_C110 22 #define CONFIG_SYS_CLK_FREQ_C110 24000000 23 #endif 24 25 /* s5pc110: return pll clock frequency */ 26 static unsigned long s5pc100_get_pll_clk(int pllreg) 27 { 28 struct s5pc100_clock *clk = 29 (struct s5pc100_clock *)samsung_get_base_clock(); 30 unsigned long r, m, p, s, mask, fout; 31 unsigned int freq; 32 33 switch (pllreg) { 34 case APLL: 35 r = readl(&clk->apll_con); 36 break; 37 case MPLL: 38 r = readl(&clk->mpll_con); 39 break; 40 case EPLL: 41 r = readl(&clk->epll_con); 42 break; 43 case HPLL: 44 r = readl(&clk->hpll_con); 45 break; 46 default: 47 printf("Unsupported PLL (%d)\n", pllreg); 48 return 0; 49 } 50 51 /* 52 * APLL_CON: MIDV [25:16] 53 * MPLL_CON: MIDV [23:16] 54 * EPLL_CON: MIDV [23:16] 55 * HPLL_CON: MIDV [23:16] 56 */ 57 if (pllreg == APLL) 58 mask = 0x3ff; 59 else 60 mask = 0x0ff; 61 62 m = (r >> 16) & mask; 63 64 /* PDIV [13:8] */ 65 p = (r >> 8) & 0x3f; 66 /* SDIV [2:0] */ 67 s = r & 0x7; 68 69 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */ 70 freq = CONFIG_SYS_CLK_FREQ_C100; 71 fout = m * (freq / (p * (1 << s))); 72 73 return fout; 74 } 75 76 /* s5pc100: return pll clock frequency */ 77 static unsigned long s5pc110_get_pll_clk(int pllreg) 78 { 79 struct s5pc110_clock *clk = 80 (struct s5pc110_clock *)samsung_get_base_clock(); 81 unsigned long r, m, p, s, mask, fout; 82 unsigned int freq; 83 84 switch (pllreg) { 85 case APLL: 86 r = readl(&clk->apll_con); 87 break; 88 case MPLL: 89 r = readl(&clk->mpll_con); 90 break; 91 case EPLL: 92 r = readl(&clk->epll_con); 93 break; 94 case VPLL: 95 r = readl(&clk->vpll_con); 96 break; 97 default: 98 printf("Unsupported PLL (%d)\n", pllreg); 99 return 0; 100 } 101 102 /* 103 * APLL_CON: MIDV [25:16] 104 * MPLL_CON: MIDV [25:16] 105 * EPLL_CON: MIDV [24:16] 106 * VPLL_CON: MIDV [24:16] 107 */ 108 if (pllreg == APLL || pllreg == MPLL) 109 mask = 0x3ff; 110 else 111 mask = 0x1ff; 112 113 m = (r >> 16) & mask; 114 115 /* PDIV [13:8] */ 116 p = (r >> 8) & 0x3f; 117 /* SDIV [2:0] */ 118 s = r & 0x7; 119 120 freq = CONFIG_SYS_CLK_FREQ_C110; 121 if (pllreg == APLL) { 122 if (s < 1) 123 s = 1; 124 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */ 125 fout = m * (freq / (p * (1 << (s - 1)))); 126 } else 127 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */ 128 fout = m * (freq / (p * (1 << s))); 129 130 return fout; 131 } 132 133 /* s5pc110: return ARM clock frequency */ 134 static unsigned long s5pc110_get_arm_clk(void) 135 { 136 struct s5pc110_clock *clk = 137 (struct s5pc110_clock *)samsung_get_base_clock(); 138 unsigned long div; 139 unsigned long dout_apll, armclk; 140 unsigned int apll_ratio; 141 142 div = readl(&clk->div0); 143 144 /* APLL_RATIO: [2:0] */ 145 apll_ratio = div & 0x7; 146 147 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1); 148 armclk = dout_apll; 149 150 return armclk; 151 } 152 153 /* s5pc100: return ARM clock frequency */ 154 static unsigned long s5pc100_get_arm_clk(void) 155 { 156 struct s5pc100_clock *clk = 157 (struct s5pc100_clock *)samsung_get_base_clock(); 158 unsigned long div; 159 unsigned long dout_apll, armclk; 160 unsigned int apll_ratio, arm_ratio; 161 162 div = readl(&clk->div0); 163 164 /* ARM_RATIO: [6:4] */ 165 arm_ratio = (div >> 4) & 0x7; 166 /* APLL_RATIO: [0] */ 167 apll_ratio = div & 0x1; 168 169 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1); 170 armclk = dout_apll / (arm_ratio + 1); 171 172 return armclk; 173 } 174 175 /* s5pc100: return HCLKD0 frequency */ 176 static unsigned long get_hclk(void) 177 { 178 struct s5pc100_clock *clk = 179 (struct s5pc100_clock *)samsung_get_base_clock(); 180 unsigned long hclkd0; 181 uint div, d0_bus_ratio; 182 183 div = readl(&clk->div0); 184 /* D0_BUS_RATIO: [10:8] */ 185 d0_bus_ratio = (div >> 8) & 0x7; 186 187 hclkd0 = get_arm_clk() / (d0_bus_ratio + 1); 188 189 return hclkd0; 190 } 191 192 /* s5pc100: return PCLKD1 frequency */ 193 static unsigned long get_pclkd1(void) 194 { 195 struct s5pc100_clock *clk = 196 (struct s5pc100_clock *)samsung_get_base_clock(); 197 unsigned long d1_bus, pclkd1; 198 uint div, d1_bus_ratio, pclkd1_ratio; 199 200 div = readl(&clk->div0); 201 /* D1_BUS_RATIO: [14:12] */ 202 d1_bus_ratio = (div >> 12) & 0x7; 203 /* PCLKD1_RATIO: [18:16] */ 204 pclkd1_ratio = (div >> 16) & 0x7; 205 206 /* ASYNC Mode */ 207 d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1); 208 pclkd1 = d1_bus / (pclkd1_ratio + 1); 209 210 return pclkd1; 211 } 212 213 /* s5pc110: return HCLKs frequency */ 214 static unsigned long get_hclk_sys(int dom) 215 { 216 struct s5pc110_clock *clk = 217 (struct s5pc110_clock *)samsung_get_base_clock(); 218 unsigned long hclk; 219 unsigned int div; 220 unsigned int offset; 221 unsigned int hclk_sys_ratio; 222 223 if (dom == CLK_M) 224 return get_hclk(); 225 226 div = readl(&clk->div0); 227 228 /* 229 * HCLK_MSYS_RATIO: [10:8] 230 * HCLK_DSYS_RATIO: [19:16] 231 * HCLK_PSYS_RATIO: [27:24] 232 */ 233 offset = 8 + (dom << 0x3); 234 235 hclk_sys_ratio = (div >> offset) & 0xf; 236 237 hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1); 238 239 return hclk; 240 } 241 242 /* s5pc110: return PCLKs frequency */ 243 static unsigned long get_pclk_sys(int dom) 244 { 245 struct s5pc110_clock *clk = 246 (struct s5pc110_clock *)samsung_get_base_clock(); 247 unsigned long pclk; 248 unsigned int div; 249 unsigned int offset; 250 unsigned int pclk_sys_ratio; 251 252 div = readl(&clk->div0); 253 254 /* 255 * PCLK_MSYS_RATIO: [14:12] 256 * PCLK_DSYS_RATIO: [22:20] 257 * PCLK_PSYS_RATIO: [30:28] 258 */ 259 offset = 12 + (dom << 0x3); 260 261 pclk_sys_ratio = (div >> offset) & 0x7; 262 263 pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1); 264 265 return pclk; 266 } 267 268 /* s5pc110: return peripheral clock frequency */ 269 static unsigned long s5pc110_get_pclk(void) 270 { 271 return get_pclk_sys(CLK_P); 272 } 273 274 /* s5pc100: return peripheral clock frequency */ 275 static unsigned long s5pc100_get_pclk(void) 276 { 277 return get_pclkd1(); 278 } 279 280 /* s5pc1xx: return uart clock frequency */ 281 static unsigned long s5pc1xx_get_uart_clk(int dev_index) 282 { 283 if (cpu_is_s5pc110()) 284 return s5pc110_get_pclk(); 285 else 286 return s5pc100_get_pclk(); 287 } 288 289 /* s5pc1xx: return pwm clock frequency */ 290 static unsigned long s5pc1xx_get_pwm_clk(void) 291 { 292 if (cpu_is_s5pc110()) 293 return s5pc110_get_pclk(); 294 else 295 return s5pc100_get_pclk(); 296 } 297 298 unsigned long get_pll_clk(int pllreg) 299 { 300 if (cpu_is_s5pc110()) 301 return s5pc110_get_pll_clk(pllreg); 302 else 303 return s5pc100_get_pll_clk(pllreg); 304 } 305 306 unsigned long get_arm_clk(void) 307 { 308 if (cpu_is_s5pc110()) 309 return s5pc110_get_arm_clk(); 310 else 311 return s5pc100_get_arm_clk(); 312 } 313 314 unsigned long get_pwm_clk(void) 315 { 316 return s5pc1xx_get_pwm_clk(); 317 } 318 319 unsigned long get_uart_clk(int dev_index) 320 { 321 return s5pc1xx_get_uart_clk(dev_index); 322 } 323 324 void set_mmc_clk(int dev_index, unsigned int div) 325 { 326 /* Do NOTHING */ 327 } 328