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