Chin Liang See | cb35060 | 2014-03-04 22:13:53 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 Altera Corporation <www.altera.com> |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0+ |
| 5 | */ |
| 6 | |
| 7 | #include <common.h> |
| 8 | #include <asm/io.h> |
| 9 | #include <asm/arch/clock_manager.h> |
| 10 | |
| 11 | static const struct socfpga_clock_manager *clock_manager_base = |
| 12 | (void *)SOCFPGA_CLKMGR_ADDRESS; |
| 13 | |
| 14 | #define CLKMGR_BYPASS_ENABLE 1 |
| 15 | #define CLKMGR_BYPASS_DISABLE 0 |
| 16 | #define CLKMGR_STAT_IDLE 0 |
| 17 | #define CLKMGR_STAT_BUSY 1 |
| 18 | #define CLKMGR_BYPASS_PERPLLSRC_SELECT_EOSC1 0 |
| 19 | #define CLKMGR_BYPASS_PERPLLSRC_SELECT_INPUT_MUX 1 |
| 20 | #define CLKMGR_BYPASS_SDRPLLSRC_SELECT_EOSC1 0 |
| 21 | #define CLKMGR_BYPASS_SDRPLLSRC_SELECT_INPUT_MUX 1 |
| 22 | |
| 23 | #define CLEAR_BGP_EN_PWRDN \ |
| 24 | (CLKMGR_MAINPLLGRP_VCO_PWRDN_SET(0)| \ |
| 25 | CLKMGR_MAINPLLGRP_VCO_EN_SET(0)| \ |
| 26 | CLKMGR_MAINPLLGRP_VCO_BGPWRDN_SET(0)) |
| 27 | |
| 28 | #define VCO_EN_BASE \ |
| 29 | (CLKMGR_MAINPLLGRP_VCO_PWRDN_SET(0)| \ |
| 30 | CLKMGR_MAINPLLGRP_VCO_EN_SET(1)| \ |
| 31 | CLKMGR_MAINPLLGRP_VCO_BGPWRDN_SET(0)) |
| 32 | |
| 33 | static inline void cm_wait_for_lock(uint32_t mask) |
| 34 | { |
| 35 | register uint32_t inter_val; |
| 36 | do { |
| 37 | inter_val = readl(&clock_manager_base->inter) & mask; |
| 38 | } while (inter_val != mask); |
| 39 | } |
| 40 | |
| 41 | /* function to poll in the fsm busy bit */ |
| 42 | static inline void cm_wait_for_fsm(void) |
| 43 | { |
| 44 | while (readl(&clock_manager_base->stat) & CLKMGR_STAT_BUSY) |
| 45 | ; |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | * function to write the bypass register which requires a poll of the |
| 50 | * busy bit |
| 51 | */ |
| 52 | static inline void cm_write_bypass(uint32_t val) |
| 53 | { |
| 54 | writel(val, &clock_manager_base->bypass); |
| 55 | cm_wait_for_fsm(); |
| 56 | } |
| 57 | |
| 58 | /* function to write the ctrl register which requires a poll of the busy bit */ |
| 59 | static inline void cm_write_ctrl(uint32_t val) |
| 60 | { |
| 61 | writel(val, &clock_manager_base->ctrl); |
| 62 | cm_wait_for_fsm(); |
| 63 | } |
| 64 | |
| 65 | /* function to write a clock register that has phase information */ |
| 66 | static inline void cm_write_with_phase(uint32_t value, |
| 67 | uint32_t reg_address, uint32_t mask) |
| 68 | { |
| 69 | /* poll until phase is zero */ |
| 70 | while (readl(reg_address) & mask) |
| 71 | ; |
| 72 | |
| 73 | writel(value, reg_address); |
| 74 | |
| 75 | while (readl(reg_address) & mask) |
| 76 | ; |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | * Setup clocks while making no assumptions about previous state of the clocks. |
| 81 | * |
| 82 | * Start by being paranoid and gate all sw managed clocks |
| 83 | * Put all plls in bypass |
| 84 | * Put all plls VCO registers back to reset value (bandgap power down). |
| 85 | * Put peripheral and main pll src to reset value to avoid glitch. |
| 86 | * Delay 5 us. |
| 87 | * Deassert bandgap power down and set numerator and denominator |
| 88 | * Start 7 us timer. |
| 89 | * set internal dividers |
| 90 | * Wait for 7 us timer. |
| 91 | * Enable plls |
| 92 | * Set external dividers while plls are locking |
| 93 | * Wait for pll lock |
| 94 | * Assert/deassert outreset all. |
| 95 | * Take all pll's out of bypass |
| 96 | * Clear safe mode |
| 97 | * set source main and peripheral clocks |
| 98 | * Ungate clocks |
| 99 | */ |
| 100 | |
| 101 | void cm_basic_init(const cm_config_t *cfg) |
| 102 | { |
| 103 | uint32_t start, timeout; |
| 104 | |
| 105 | /* Start by being paranoid and gate all sw managed clocks */ |
| 106 | |
| 107 | /* |
| 108 | * We need to disable nandclk |
| 109 | * and then do another apb access before disabling |
| 110 | * gatting off the rest of the periperal clocks. |
| 111 | */ |
| 112 | writel(~CLKMGR_PERPLLGRP_EN_NANDCLK_MASK & |
| 113 | readl(&clock_manager_base->per_pll_en), |
| 114 | &clock_manager_base->per_pll_en); |
| 115 | |
| 116 | /* DO NOT GATE OFF DEBUG CLOCKS & BRIDGE CLOCKS */ |
| 117 | writel(CLKMGR_MAINPLLGRP_EN_DBGTIMERCLK_MASK | |
| 118 | CLKMGR_MAINPLLGRP_EN_DBGTRACECLK_MASK | |
| 119 | CLKMGR_MAINPLLGRP_EN_DBGCLK_MASK | |
| 120 | CLKMGR_MAINPLLGRP_EN_DBGATCLK_MASK | |
| 121 | CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK | |
| 122 | CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK, |
| 123 | &clock_manager_base->main_pll_en); |
| 124 | |
| 125 | writel(0, &clock_manager_base->sdr_pll_en); |
| 126 | |
| 127 | /* now we can gate off the rest of the peripheral clocks */ |
| 128 | writel(0, &clock_manager_base->per_pll_en); |
| 129 | |
| 130 | /* Put all plls in bypass */ |
| 131 | cm_write_bypass( |
| 132 | CLKMGR_BYPASS_PERPLLSRC_SET( |
| 133 | CLKMGR_BYPASS_PERPLLSRC_SELECT_EOSC1) | |
| 134 | CLKMGR_BYPASS_SDRPLLSRC_SET( |
| 135 | CLKMGR_BYPASS_SDRPLLSRC_SELECT_EOSC1) | |
| 136 | CLKMGR_BYPASS_PERPLL_SET(CLKMGR_BYPASS_ENABLE) | |
| 137 | CLKMGR_BYPASS_SDRPLL_SET(CLKMGR_BYPASS_ENABLE) | |
| 138 | CLKMGR_BYPASS_MAINPLL_SET(CLKMGR_BYPASS_ENABLE)); |
| 139 | |
| 140 | /* |
| 141 | * Put all plls VCO registers back to reset value. |
| 142 | * Some code might have messed with them. |
| 143 | */ |
| 144 | writel(CLKMGR_MAINPLLGRP_VCO_RESET_VALUE, |
| 145 | &clock_manager_base->main_pll_vco); |
| 146 | writel(CLKMGR_PERPLLGRP_VCO_RESET_VALUE, |
| 147 | &clock_manager_base->per_pll_vco); |
| 148 | writel(CLKMGR_SDRPLLGRP_VCO_RESET_VALUE, |
| 149 | &clock_manager_base->sdr_pll_vco); |
| 150 | |
| 151 | /* |
| 152 | * The clocks to the flash devices and the L4_MAIN clocks can |
| 153 | * glitch when coming out of safe mode if their source values |
| 154 | * are different from their reset value. So the trick it to |
| 155 | * put them back to their reset state, and change input |
| 156 | * after exiting safe mode but before ungating the clocks. |
| 157 | */ |
| 158 | writel(CLKMGR_PERPLLGRP_SRC_RESET_VALUE, |
| 159 | &clock_manager_base->per_pll_src); |
| 160 | writel(CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE, |
| 161 | &clock_manager_base->main_pll_l4src); |
| 162 | |
| 163 | /* read back for the required 5 us delay. */ |
| 164 | readl(&clock_manager_base->main_pll_vco); |
| 165 | readl(&clock_manager_base->per_pll_vco); |
| 166 | readl(&clock_manager_base->sdr_pll_vco); |
| 167 | |
| 168 | |
| 169 | /* |
| 170 | * We made sure bgpwr down was assert for 5 us. Now deassert BG PWR DN |
| 171 | * with numerator and denominator. |
| 172 | */ |
| 173 | writel(cfg->main_vco_base | CLEAR_BGP_EN_PWRDN | |
| 174 | CLKMGR_MAINPLLGRP_VCO_REGEXTSEL_MASK, |
| 175 | &clock_manager_base->main_pll_vco); |
| 176 | |
| 177 | writel(cfg->peri_vco_base | CLEAR_BGP_EN_PWRDN | |
| 178 | CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK, |
| 179 | &clock_manager_base->per_pll_vco); |
| 180 | |
| 181 | writel(CLKMGR_SDRPLLGRP_VCO_OUTRESET_SET(0) | |
| 182 | CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(0) | |
| 183 | cfg->sdram_vco_base | CLEAR_BGP_EN_PWRDN | |
| 184 | CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK, |
| 185 | &clock_manager_base->sdr_pll_vco); |
| 186 | |
| 187 | /* |
| 188 | * Time starts here |
| 189 | * must wait 7 us from BGPWRDN_SET(0) to VCO_ENABLE_SET(1) |
| 190 | */ |
| 191 | reset_timer(); |
| 192 | start = get_timer(0); |
| 193 | /* timeout in unit of us as CONFIG_SYS_HZ = 1000*1000 */ |
| 194 | timeout = 7; |
| 195 | |
| 196 | /* main mpu */ |
| 197 | writel(cfg->mpuclk, &clock_manager_base->main_pll_mpuclk); |
| 198 | |
| 199 | /* main main clock */ |
| 200 | writel(cfg->mainclk, &clock_manager_base->main_pll_mainclk); |
| 201 | |
| 202 | /* main for dbg */ |
| 203 | writel(cfg->dbgatclk, &clock_manager_base->main_pll_dbgatclk); |
| 204 | |
| 205 | /* main for cfgs2fuser0clk */ |
| 206 | writel(cfg->cfg2fuser0clk, |
| 207 | &clock_manager_base->main_pll_cfgs2fuser0clk); |
| 208 | |
| 209 | /* Peri emac0 50 MHz default to RMII */ |
| 210 | writel(cfg->emac0clk, &clock_manager_base->per_pll_emac0clk); |
| 211 | |
| 212 | /* Peri emac1 50 MHz default to RMII */ |
| 213 | writel(cfg->emac1clk, &clock_manager_base->per_pll_emac1clk); |
| 214 | |
| 215 | /* Peri QSPI */ |
| 216 | writel(cfg->mainqspiclk, &clock_manager_base->main_pll_mainqspiclk); |
| 217 | |
| 218 | writel(cfg->perqspiclk, &clock_manager_base->per_pll_perqspiclk); |
| 219 | |
| 220 | /* Peri pernandsdmmcclk */ |
| 221 | writel(cfg->pernandsdmmcclk, |
| 222 | &clock_manager_base->per_pll_pernandsdmmcclk); |
| 223 | |
| 224 | /* Peri perbaseclk */ |
| 225 | writel(cfg->perbaseclk, &clock_manager_base->per_pll_perbaseclk); |
| 226 | |
| 227 | /* Peri s2fuser1clk */ |
| 228 | writel(cfg->s2fuser1clk, &clock_manager_base->per_pll_s2fuser1clk); |
| 229 | |
| 230 | /* 7 us must have elapsed before we can enable the VCO */ |
| 231 | while (get_timer(start) < timeout) |
| 232 | ; |
| 233 | |
| 234 | /* Enable vco */ |
| 235 | /* main pll vco */ |
| 236 | writel(cfg->main_vco_base | VCO_EN_BASE, |
| 237 | &clock_manager_base->main_pll_vco); |
| 238 | |
| 239 | /* periferal pll */ |
| 240 | writel(cfg->peri_vco_base | VCO_EN_BASE, |
| 241 | &clock_manager_base->per_pll_vco); |
| 242 | |
| 243 | /* sdram pll vco */ |
| 244 | writel(CLKMGR_SDRPLLGRP_VCO_OUTRESET_SET(0) | |
| 245 | CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(0) | |
| 246 | cfg->sdram_vco_base | VCO_EN_BASE, |
| 247 | &clock_manager_base->sdr_pll_vco); |
| 248 | |
| 249 | /* L3 MP and L3 SP */ |
| 250 | writel(cfg->maindiv, &clock_manager_base->main_pll_maindiv); |
| 251 | |
| 252 | writel(cfg->dbgdiv, &clock_manager_base->main_pll_dbgdiv); |
| 253 | |
| 254 | writel(cfg->tracediv, &clock_manager_base->main_pll_tracediv); |
| 255 | |
| 256 | /* L4 MP, L4 SP, can0, and can1 */ |
| 257 | writel(cfg->perdiv, &clock_manager_base->per_pll_div); |
| 258 | |
| 259 | writel(cfg->gpiodiv, &clock_manager_base->per_pll_gpiodiv); |
| 260 | |
| 261 | #define LOCKED_MASK \ |
| 262 | (CLKMGR_INTER_SDRPLLLOCKED_MASK | \ |
| 263 | CLKMGR_INTER_PERPLLLOCKED_MASK | \ |
| 264 | CLKMGR_INTER_MAINPLLLOCKED_MASK) |
| 265 | |
| 266 | cm_wait_for_lock(LOCKED_MASK); |
| 267 | |
| 268 | /* write the sdram clock counters before toggling outreset all */ |
| 269 | writel(cfg->ddrdqsclk & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK, |
| 270 | &clock_manager_base->sdr_pll_ddrdqsclk); |
| 271 | |
| 272 | writel(cfg->ddr2xdqsclk & CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_MASK, |
| 273 | &clock_manager_base->sdr_pll_ddr2xdqsclk); |
| 274 | |
| 275 | writel(cfg->ddrdqclk & CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_MASK, |
| 276 | &clock_manager_base->sdr_pll_ddrdqclk); |
| 277 | |
| 278 | writel(cfg->s2fuser2clk & CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_MASK, |
| 279 | &clock_manager_base->sdr_pll_s2fuser2clk); |
| 280 | |
| 281 | /* |
| 282 | * after locking, but before taking out of bypass |
| 283 | * assert/deassert outresetall |
| 284 | */ |
| 285 | uint32_t mainvco = readl(&clock_manager_base->main_pll_vco); |
| 286 | |
| 287 | /* assert main outresetall */ |
| 288 | writel(mainvco | CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK, |
| 289 | &clock_manager_base->main_pll_vco); |
| 290 | |
| 291 | uint32_t periphvco = readl(&clock_manager_base->per_pll_vco); |
| 292 | |
| 293 | /* assert pheriph outresetall */ |
| 294 | writel(periphvco | CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK, |
| 295 | &clock_manager_base->per_pll_vco); |
| 296 | |
| 297 | /* assert sdram outresetall */ |
| 298 | writel(cfg->sdram_vco_base | VCO_EN_BASE| |
| 299 | CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(1), |
| 300 | &clock_manager_base->sdr_pll_vco); |
| 301 | |
| 302 | /* deassert main outresetall */ |
| 303 | writel(mainvco & ~CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK, |
| 304 | &clock_manager_base->main_pll_vco); |
| 305 | |
| 306 | /* deassert pheriph outresetall */ |
| 307 | writel(periphvco & ~CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK, |
| 308 | &clock_manager_base->per_pll_vco); |
| 309 | |
| 310 | /* deassert sdram outresetall */ |
| 311 | writel(CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(0) | |
| 312 | cfg->sdram_vco_base | VCO_EN_BASE, |
| 313 | &clock_manager_base->sdr_pll_vco); |
| 314 | |
| 315 | /* |
| 316 | * now that we've toggled outreset all, all the clocks |
| 317 | * are aligned nicely; so we can change any phase. |
| 318 | */ |
| 319 | cm_write_with_phase(cfg->ddrdqsclk, |
| 320 | (uint32_t)&clock_manager_base->sdr_pll_ddrdqsclk, |
| 321 | CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK); |
| 322 | |
| 323 | /* SDRAM DDR2XDQSCLK */ |
| 324 | cm_write_with_phase(cfg->ddr2xdqsclk, |
| 325 | (uint32_t)&clock_manager_base->sdr_pll_ddr2xdqsclk, |
| 326 | CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_MASK); |
| 327 | |
| 328 | cm_write_with_phase(cfg->ddrdqclk, |
| 329 | (uint32_t)&clock_manager_base->sdr_pll_ddrdqclk, |
| 330 | CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_MASK); |
| 331 | |
| 332 | cm_write_with_phase(cfg->s2fuser2clk, |
| 333 | (uint32_t)&clock_manager_base->sdr_pll_s2fuser2clk, |
| 334 | CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK); |
| 335 | |
| 336 | /* Take all three PLLs out of bypass when safe mode is cleared. */ |
| 337 | cm_write_bypass( |
| 338 | CLKMGR_BYPASS_PERPLLSRC_SET( |
| 339 | CLKMGR_BYPASS_PERPLLSRC_SELECT_EOSC1) | |
| 340 | CLKMGR_BYPASS_SDRPLLSRC_SET( |
| 341 | CLKMGR_BYPASS_SDRPLLSRC_SELECT_EOSC1) | |
| 342 | CLKMGR_BYPASS_PERPLL_SET(CLKMGR_BYPASS_DISABLE) | |
| 343 | CLKMGR_BYPASS_SDRPLL_SET(CLKMGR_BYPASS_DISABLE) | |
| 344 | CLKMGR_BYPASS_MAINPLL_SET(CLKMGR_BYPASS_DISABLE)); |
| 345 | |
| 346 | /* clear safe mode */ |
| 347 | cm_write_ctrl(readl(&clock_manager_base->ctrl) | |
| 348 | CLKMGR_CTRL_SAFEMODE_SET(CLKMGR_CTRL_SAFEMODE_MASK)); |
| 349 | |
| 350 | /* |
| 351 | * now that safe mode is clear with clocks gated |
| 352 | * it safe to change the source mux for the flashes the the L4_MAIN |
| 353 | */ |
| 354 | writel(cfg->persrc, &clock_manager_base->per_pll_src); |
| 355 | writel(cfg->l4src, &clock_manager_base->main_pll_l4src); |
| 356 | |
| 357 | /* Now ungate non-hw-managed clocks */ |
| 358 | writel(~0, &clock_manager_base->main_pll_en); |
| 359 | writel(~0, &clock_manager_base->per_pll_en); |
| 360 | writel(~0, &clock_manager_base->sdr_pll_en); |
| 361 | } |