Angel Pons | a2ee761 | 2020-04-04 18:51:15 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 2 | |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 3 | #include <device/mmio.h> |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 4 | #include <assert.h> |
| 5 | #include <console/console.h> |
| 6 | #include <delay.h> |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 7 | #include <soc/addressmap.h> |
| 8 | #include <soc/clk_rst.h> |
| 9 | #include <soc/clock.h> |
| 10 | #include <soc/clst_clk.h> |
Andre Heider | 92712d3 | 2018-02-16 12:44:11 +0100 | [diff] [blame] | 11 | #include <soc/console_uart.h> |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 12 | #include <soc/flow.h> |
| 13 | #include <soc/maincpu.h> |
| 14 | #include <soc/pmc.h> |
| 15 | #include <soc/sysctr.h> |
| 16 | |
| 17 | static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE; |
| 18 | static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE; |
| 19 | static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE; |
| 20 | |
| 21 | enum { |
| 22 | PLLX_INDEX, |
| 23 | PLLC_INDEX, |
| 24 | PLLU_INDEX, |
| 25 | PLLDP_INDEX, |
| 26 | PLLD_INDEX, |
| 27 | PLL_MAX_INDEX, |
| 28 | }; |
| 29 | |
| 30 | struct pll_reg_info { |
| 31 | u32 *base_reg; |
| 32 | u32 *lock_enb_reg; |
| 33 | u32 lock_enb_val; |
| 34 | u32 *pll_lock_reg; |
| 35 | u32 pll_lock_val; |
| 36 | u32 *kcp_kvco_reg; |
| 37 | u32 n_shift:5; /* n bits location */ |
| 38 | u32 m_shift:5; /* m bits location */ |
| 39 | u32 p_shift:5; /* p bits location */ |
| 40 | u32 kcp_shift:5; /* kcp bits location */ |
| 41 | u32 kvco_shift:5; /* kvco bit location */ |
| 42 | u32 rsvd:7; |
| 43 | } static const pll_reg_table[] = { |
| 44 | [PLLX_INDEX] = { .base_reg = CLK_RST_REG(pllx_base), |
| 45 | .lock_enb_reg = CLK_RST_REG(pllx_misc), |
| 46 | .lock_enb_val = PLLPAXS_MISC_LOCK_ENABLE, |
| 47 | .pll_lock_reg = CLK_RST_REG(pllx_base), |
| 48 | .pll_lock_val = PLL_BASE_LOCK, |
| 49 | .kcp_kvco_reg = CLK_RST_REG(pllx_misc3), |
| 50 | .n_shift = 8, .m_shift = 0, .p_shift = 20, |
| 51 | .kcp_shift = 1, .kvco_shift = 0, }, |
| 52 | [PLLC_INDEX] = { .base_reg = CLK_RST_REG(pllc_base), |
| 53 | .lock_enb_reg = CLK_RST_REG(pllc_misc), |
| 54 | .pll_lock_reg = CLK_RST_REG(pllc_base), |
| 55 | .pll_lock_val = PLL_BASE_LOCK, |
| 56 | .n_shift = 10, .m_shift = 0, .p_shift = 20, }, |
| 57 | [PLLU_INDEX] = { .base_reg = CLK_RST_REG(pllu_base), |
| 58 | .lock_enb_reg = CLK_RST_REG(pllu_misc), |
| 59 | .lock_enb_val = PLLU_MISC_LOCK_ENABLE, |
| 60 | .pll_lock_reg = CLK_RST_REG(pllu_base), |
| 61 | .pll_lock_val = PLL_BASE_LOCK, |
| 62 | .kcp_kvco_reg = CLK_RST_REG(pllu_misc), |
| 63 | .n_shift = 8, .m_shift = 0, .p_shift = 16, |
| 64 | .kcp_shift = 25, .kvco_shift = 24, }, |
| 65 | [PLLDP_INDEX] = { .base_reg = CLK_RST_REG(plldp_base), |
| 66 | .lock_enb_reg = CLK_RST_REG(plldp_misc), |
| 67 | .lock_enb_val = PLLDPD2_MISC_LOCK_ENABLE, |
| 68 | .pll_lock_reg = CLK_RST_REG(plldp_base), |
| 69 | .pll_lock_val = PLL_BASE_LOCK, |
| 70 | .kcp_kvco_reg = CLK_RST_REG(plldp_misc), |
| 71 | .n_shift = 8, .m_shift = 0, .p_shift = 19, |
| 72 | .kcp_shift = 25, .kvco_shift = 24, }, |
| 73 | [PLLD_INDEX] = { .base_reg = CLK_RST_REG(plld_base), |
| 74 | .lock_enb_reg = CLK_RST_REG(plld_misc), |
| 75 | .lock_enb_val = PLLD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE, |
| 76 | .pll_lock_reg = CLK_RST_REG(plld_base), |
| 77 | .pll_lock_val = PLL_BASE_LOCK, |
| 78 | .kcp_kvco_reg = CLK_RST_REG(plld_misc), |
| 79 | .n_shift = 11, .m_shift = 0, .p_shift = 20, |
| 80 | .kcp_shift = 23, .kvco_shift = 22, }, |
| 81 | }; |
| 82 | |
| 83 | struct pll_fields { |
| 84 | u32 n:8; /* the feedback divider bits width */ |
| 85 | u32 m:8; /* the input divider bits width */ |
| 86 | u32 p:5; /* the post divider bits witch */ |
| 87 | u32 kcp:2; /* charge pump gain control */ |
| 88 | u32 kvco:1; /* vco gain */ |
| 89 | u32 rsvd:8; |
| 90 | }; |
| 91 | |
| 92 | #define PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco) \ |
| 93 | {.n = _n, .m = _m, .p = _p, .kcp = _kcp, .kvco = _kvco,} |
| 94 | #define PLL_NO_KCP_KVCO(_n, _m, _p) \ |
| 95 | {.n = _n, .m = _m, .p = _p,} |
| 96 | |
| 97 | #define PLLX(_n, _m, _p, _kcp, _kvco) \ |
| 98 | [PLLX_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco) |
| 99 | #define PLLC(_n, _m, _p) \ |
| 100 | [PLLC_INDEX] = PLL_NO_KCP_KVCO(_n, _m, _p) |
| 101 | #define PLLU(_n, _m, _p, _kcp, _kvco) \ |
| 102 | [PLLU_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco) |
| 103 | #define PLLDP(_n, _m, _p, _kcp, _kvco) \ |
| 104 | [PLLDP_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco) |
| 105 | #define PLLD(_n, _m, _p, _kcp, _kvco) \ |
| 106 | [PLLD_INDEX] = PLL_HAS_KCP_KVCO(_n, _m, _p, _kcp, _kvco) |
| 107 | |
| 108 | /* This table defines the frequency dividers for every PLL to turn the external |
| 109 | * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h. |
| 110 | * All PLLs have three dividers (n, m and p), with the governing formula for |
| 111 | * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p). |
| 112 | * All divisor configurations must meet the PLL's constraints for VCO and CF: |
| 113 | * PLLX: 12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz |
| 114 | * PLLC: 12 MHz < CF < 50 MHz, 600 MHz < VCO < 1400 MHz |
| 115 | * PLLM: 12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz |
| 116 | * PLLP: 1 MHz < CF < 6 MHz, 200 MHz < VCO < 700 MHz |
| 117 | * PLLD: 1 MHz < CF < 6 MHz, 500 MHz < VCO < 1000 MHz |
| 118 | * PLLU: 1 MHz < CF < 6 MHz, 480 MHz < VCO < 960 MHz |
| 119 | * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz |
| 120 | * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c). |
| 121 | * Target Frequencies: |
| 122 | * PLLX = CONFIG_PLLX_KHZ |
| 123 | * PLLC = 600 MHz |
| 124 | * PLLU = 240 MHz (As per TRM, m and n should be programmed to generate 480MHz |
| 125 | * VCO, and p should be programmed to do div-by-2.) |
| 126 | * PLLDP = 270 MHz (PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6)). |
| 127 | * PLLM is set up dynamically by clock_sdram(). |
| 128 | * PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD). |
| 129 | */ |
| 130 | struct { |
| 131 | int khz; |
| 132 | struct pll_fields plls[PLL_MAX_INDEX]; |
| 133 | } static osc_table[16] = { |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 134 | [OSC_FREQ_12] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 135 | .khz = 12000, |
| 136 | .plls = { |
| 137 | PLLX(TEGRA_PLLX_KHZ / 12000, 1, 0, 0, 0), |
| 138 | PLLC(50, 1, 0), /* 600 MHz */ |
| 139 | PLLU(40, 1, 1, 0, 0), /* 240 MHz */ |
| 140 | PLLDP(90, 1, 2, 0, 0), /* 270 MHz */ |
| 141 | }, |
| 142 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 143 | [OSC_FREQ_13] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 144 | .khz = 13000, |
| 145 | .plls = { |
| 146 | PLLX(TEGRA_PLLX_KHZ / 13000, 1, 0, 0, 0), |
| 147 | PLLC(46, 1, 0), /* 598.0 MHz */ |
| 148 | PLLU(74, 2, 1, 0, 0), /* 240.5 MHz */ |
| 149 | PLLDP(83, 1, 3, 0, 0), /* 269.8 MHz */ |
| 150 | }, |
| 151 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 152 | [OSC_FREQ_16P8] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 153 | .khz = 16800, |
| 154 | .plls = { |
| 155 | PLLX(TEGRA_PLLX_KHZ / 16800, 1, 0, 0, 0), |
| 156 | PLLC(71, 1, 1), /* 596.4 MHz */ |
| 157 | PLLU(115, 4, 1, 0, 0), /* 241.5 MHz */ |
| 158 | PLLDP(64, 1, 2, 0, 0), /* 268.8 MHz */ |
| 159 | }, |
| 160 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 161 | [OSC_FREQ_19P2] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 162 | .khz = 19200, |
| 163 | .plls = { |
| 164 | PLLX(TEGRA_PLLX_KHZ / 19200, 1, 0, 0, 0), |
| 165 | PLLC(62, 1, 1), /* 595.2 MHz */ |
| 166 | PLLU(25, 1, 1, 0, 0), /* 240.0 MHz */ |
| 167 | PLLDP(56, 1, 2, 0, 0), /* 268.8 MHz */ |
| 168 | }, |
| 169 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 170 | [OSC_FREQ_26] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 171 | .khz = 26000, |
| 172 | .plls = { |
| 173 | PLLX(TEGRA_PLLX_KHZ / 26000, 1, 0, 0, 0), |
| 174 | PLLC(23, 1, 0), /* 598.0 MHz */ |
| 175 | PLLU(37, 2, 1, 0, 0), /* 240.5 MHz */ |
| 176 | PLLDP(83, 2, 2, 0, 0), /* 269.8 MHz */ |
| 177 | }, |
| 178 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 179 | [OSC_FREQ_38P4] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 180 | .khz = 38400, |
| 181 | .plls = { |
| 182 | PLLX(TEGRA_PLLX_KHZ / 38400, 1, 0, 0, 0), |
| 183 | PLLC(62, 2, 1), /* 595.2 MHz */ |
| 184 | PLLU(25, 2, 1, 0, 0), /* 240 MHz */ |
| 185 | PLLDP(56, 2, 2, 0, 0), /* 268.8 MHz */ |
| 186 | }, |
| 187 | }, |
Stefan Reinauer | 2687d93 | 2015-07-09 00:17:02 +0200 | [diff] [blame] | 188 | [OSC_FREQ_48] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 189 | .khz = 48000, |
| 190 | .plls = { |
| 191 | PLLX(TEGRA_PLLX_KHZ / 48000, 1, 0, 0, 0), |
| 192 | PLLC(50, 2, 1), /* 600 MHz */ |
| 193 | PLLU(40, 4, 1, 0, 0), /* 240 MHz */ |
| 194 | PLLDP(90, 2, 3, 0, 0), /* 270 MHz */ |
| 195 | }, |
| 196 | }, |
| 197 | }; |
| 198 | |
| 199 | /* Get the oscillator frequency, from the corresponding hardware |
| 200 | * configuration field. This is actually a per-soc thing. Avoid the |
| 201 | * temptation to make it common. |
| 202 | */ |
| 203 | static u32 clock_get_osc_bits(void) |
| 204 | { |
| 205 | return (read32(CLK_RST_REG(osc_ctrl)) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; |
| 206 | } |
| 207 | |
| 208 | int clock_get_osc_khz(void) |
| 209 | { |
| 210 | return osc_table[clock_get_osc_bits()].khz; |
| 211 | } |
| 212 | |
| 213 | int clock_get_pll_input_khz(void) |
| 214 | { |
| 215 | u32 osc_ctrl = read32(CLK_RST_REG(osc_ctrl)); |
| 216 | u32 osc_bits = (osc_ctrl & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; |
| 217 | u32 pll_ref_div = (osc_ctrl & OSC_PREDIV_MASK) >> OSC_PREDIV_SHIFT; |
| 218 | return osc_table[osc_bits].khz >> pll_ref_div; |
| 219 | } |
| 220 | |
| 221 | void clock_init_arm_generic_timer(void) |
| 222 | { |
| 223 | uint32_t freq = TEGRA_CLK_M_KHZ * 1000; |
| 224 | |
| 225 | // Record the system timer frequency. |
| 226 | write32(&sysctr->cntfid0, freq); |
| 227 | // Enable the system counter. |
| 228 | uint32_t cntcr = read32(&sysctr->cntcr); |
| 229 | cntcr |= SYSCTR_CNTCR_EN | SYSCTR_CNTCR_HDBG; |
| 230 | write32(&sysctr->cntcr, cntcr); |
| 231 | } |
| 232 | |
| 233 | #define SOR0_CLK_SEL0 (1 << 14) |
| 234 | #define SOR0_CLK_SEL1 (1 << 15) |
| 235 | |
| 236 | void sor_clock_stop(void) |
| 237 | { |
| 238 | /* The Serial Output Resource clock has to be off |
| 239 | * before we start the plldp. Learned the hard way. |
| 240 | * FIXME: this has to be cleaned up a bit more. |
| 241 | * Waiting on some new info from Nvidia. |
| 242 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 243 | clrbits32(CLK_RST_REG(clk_src_sor), SOR0_CLK_SEL0 | SOR0_CLK_SEL1); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | void sor_clock_start(void) |
| 247 | { |
| 248 | /* uses PLLP, has a non-standard bit layout. */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 249 | setbits32(CLK_RST_REG(clk_src_sor), SOR0_CLK_SEL0); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 250 | } |
| 251 | |
| 252 | static void init_pll(u32 index, u32 osc) |
| 253 | { |
| 254 | assert(index <= PLL_MAX_INDEX); |
| 255 | |
| 256 | struct pll_fields *pll = &osc_table[osc].plls[index]; |
| 257 | const struct pll_reg_info *pll_reg = &pll_reg_table[index]; |
| 258 | |
| 259 | u32 dividers = pll->n << pll_reg->n_shift | |
| 260 | pll->m << pll_reg->m_shift | |
| 261 | pll->p << pll_reg->p_shift; |
| 262 | |
| 263 | /* Write dividers but BYPASS the PLL while we're messing with it. */ |
| 264 | write32(pll_reg->base_reg, dividers | PLL_BASE_BYPASS); |
| 265 | |
| 266 | /* Set Lock bit if needed. */ |
| 267 | if (pll_reg->lock_enb_val) |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 268 | setbits32(pll_reg->lock_enb_reg, pll_reg->lock_enb_val); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 269 | |
| 270 | /* Set KCP/KVCO if needed. */ |
| 271 | if (pll_reg->kcp_kvco_reg) |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 272 | setbits32(pll_reg->kcp_kvco_reg, |
| 273 | pll->kcp << pll_reg->kcp_shift | |
| 274 | pll->kvco << pll_reg->kvco_shift); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 275 | |
| 276 | /* Enable PLL and take it back out of BYPASS */ |
| 277 | write32(pll_reg->base_reg, dividers | PLL_BASE_ENABLE); |
| 278 | |
| 279 | /* Wait for lock ready */ |
| 280 | if (pll_reg->lock_enb_val) |
| 281 | while (!(read32(pll_reg->pll_lock_reg) & pll_reg->pll_lock_val)) |
| 282 | ; |
| 283 | } |
| 284 | |
| 285 | static void init_pllc(u32 osc) |
| 286 | { |
| 287 | /* Clear PLLC reset */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 288 | clrbits32(CLK_RST_REG(pllc_misc), PLLC_MISC_RESET); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 289 | |
| 290 | /* Clear PLLC IDDQ */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 291 | clrbits32(CLK_RST_REG(pllc_misc_1), PLLC_MISC_1_IDDQ); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 292 | |
| 293 | /* Max out the AVP clock before everything else (need PLLC for that). */ |
| 294 | init_pll(PLLC_INDEX, osc); |
| 295 | |
| 296 | /* wait for pllc_lock (not the normal bit 27) */ |
| 297 | while (!(read32(CLK_RST_REG(pllc_base)) & PLLC_BASE_LOCK)) |
| 298 | ; |
| 299 | } |
| 300 | |
| 301 | static void init_pllu(u32 osc) |
| 302 | { |
| 303 | /* Clear PLLU IDDQ */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 304 | clrbits32(CLK_RST_REG(pllu_misc), PLLU_MISC_IDDQ); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 305 | |
| 306 | /* Wait 5 us */ |
| 307 | udelay(5); |
| 308 | |
| 309 | init_pll(PLLU_INDEX, osc); |
| 310 | } |
| 311 | |
| 312 | static void init_utmip_pll(void) |
| 313 | { |
| 314 | int khz = clock_get_pll_input_khz(); |
| 315 | |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 316 | /* CFG1 */ |
Tom Warren | faa76f5 | 2015-06-30 10:22:12 -0700 | [diff] [blame] | 317 | u32 pllu_enb_ct = 0; |
Elyes HAOUAS | 6df3b64 | 2018-11-26 22:53:49 +0100 | [diff] [blame] | 318 | u32 phy_stb_ct = DIV_ROUND_UP(khz, 300); /* phy_stb_ct = 128 */ |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 319 | write32(CLK_RST_REG(utmip_pll_cfg1), |
| 320 | pllu_enb_ct << UTMIP_CFG1_PLLU_ENABLE_DLY_COUNT_SHIFT | |
| 321 | UTMIP_CFG1_FORCE_PLLU_POWERDOWN_ENABLE | |
| 322 | UTMIP_CFG1_FORCE_PLL_ENABLE_POWERDOWN_DISABLE | |
| 323 | UTMIP_CFG1_FORCE_PLL_ACTIVE_POWERDOWN_DISABLE | |
| 324 | UTMIP_CFG1_FORCE_PLL_ENABLE_POWERUP_ENABLE | |
| 325 | phy_stb_ct << UTMIP_CFG1_XTAL_FREQ_COUNT_SHIFT); |
| 326 | |
| 327 | /* CFG2 */ |
Tom Warren | faa76f5 | 2015-06-30 10:22:12 -0700 | [diff] [blame] | 328 | u32 pllu_stb_ct = 0; |
Elyes HAOUAS | 6df3b64 | 2018-11-26 22:53:49 +0100 | [diff] [blame] | 329 | u32 phy_act_ct = DIV_ROUND_UP(khz, 6400); /* phy_act_ct = 6 */ |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 330 | write32(CLK_RST_REG(utmip_pll_cfg2), |
| 331 | phy_act_ct << UTMIP_CFG2_PLL_ACTIVE_DLY_COUNT_SHIFT | |
| 332 | pllu_stb_ct << UTMIP_CFG2_PLLU_STABLE_COUNT_SHIFT | |
Tom Warren | faa76f5 | 2015-06-30 10:22:12 -0700 | [diff] [blame] | 333 | UTMIP_CFG2_FORCE_PD_SAMP_D_POWERDOWN_DISABLE | |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 334 | UTMIP_CFG2_FORCE_PD_SAMP_C_POWERDOWN_DISABLE | |
| 335 | UTMIP_CFG2_FORCE_PD_SAMP_B_POWERDOWN_DISABLE | |
Tom Warren | faa76f5 | 2015-06-30 10:22:12 -0700 | [diff] [blame] | 336 | UTMIP_CFG2_FORCE_PD_SAMP_A_POWERDOWN_DISABLE | |
| 337 | UTMIP_CFG2_FORCE_PD_SAMP_D_POWERUP_ENABLE | |
| 338 | UTMIP_CFG2_FORCE_PD_SAMP_C_POWERUP_ENABLE | |
| 339 | UTMIP_CFG2_FORCE_PD_SAMP_B_POWERUP_ENABLE | |
| 340 | UTMIP_CFG2_FORCE_PD_SAMP_A_POWERUP_ENABLE); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 341 | |
Tom Warren | faa76f5 | 2015-06-30 10:22:12 -0700 | [diff] [blame] | 342 | printk(BIOS_DEBUG, "%s: UTMIPLL_HW_PWRDN_CFG0:0x%08x\n", |
| 343 | __func__, read32(CLK_RST_REG(utmipll_hw_pwrdn_cfg0))); |
| 344 | printk(BIOS_DEBUG, "%s: UTMIP_PLL_CFG0:0x%08x\n", |
| 345 | __func__, read32(CLK_RST_REG(utmip_pll_cfg0))); |
| 346 | printk(BIOS_DEBUG, "%s: UTMIP_PLL_CFG1:0x%08x\n", |
| 347 | __func__, read32(CLK_RST_REG(utmip_pll_cfg1))); |
| 348 | printk(BIOS_DEBUG, "%s: UTMIP_PLL_CFG2:0x%08x\n", |
| 349 | __func__, read32(CLK_RST_REG(utmip_pll_cfg2))); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 350 | } |
| 351 | |
| 352 | /* Graphics just has to be different. There's a few more bits we |
| 353 | * need to set in here, but it makes sense just to restrict all the |
| 354 | * special bits to this one function. |
| 355 | */ |
| 356 | static void graphics_pll(void) |
| 357 | { |
| 358 | int osc = clock_get_osc_bits(); |
| 359 | u32 *cfg = CLK_RST_REG(plldp_ss_cfg); |
| 360 | /* the vendor code sets the dither bit (28) |
| 361 | * an undocumented bit (24) |
| 362 | * and clamp while we mess with it (22) |
| 363 | * Dither is pretty important to display port |
| 364 | * so we really do need to handle these bits. |
| 365 | * I'm not willing to not clamp it, even if |
| 366 | * it might "mostly work" with it not set, |
| 367 | * I don't want to find out in a few months |
| 368 | * that it is needed. |
| 369 | */ |
| 370 | u32 scfg = (1<<28) | (1<<24) | (1<<22); |
| 371 | write32(cfg, scfg); |
| 372 | init_pll(PLLDP_INDEX, osc); |
| 373 | /* leave dither and undoc bits set, release clamp */ |
| 374 | scfg = (1<<28) | (1<<24); |
| 375 | write32(cfg, scfg); |
| 376 | } |
| 377 | |
| 378 | /* |
| 379 | * Init PLLD clock source. |
| 380 | * |
| 381 | * @frequency: the requested plld frequency |
| 382 | * |
| 383 | * Return the plld frequency if success, otherwise return 0. |
| 384 | */ |
| 385 | u32 clock_configure_plld(u32 frequency) |
| 386 | { |
| 387 | /** |
| 388 | * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz |
| 389 | * = (cf * n) >> p, where 1MHz < cf < 6MHz |
| 390 | * = ((ref / m) * n) >> p |
| 391 | * |
| 392 | * Iterate the possible values of p (3 bits, 2^7) to find out a minimum |
| 393 | * safe vco, then find best (m, n). since m has only 5 bits, we can |
| 394 | * iterate all possible values. Note Tegra1xx supports 11 bits for n, |
| 395 | * but our pll_fields has only 10 bits for n. |
| 396 | * |
| 397 | * Note values undershoot or overshoot target output frequency may not |
| 398 | * work if the values are not in "safe" range by panel specification. |
| 399 | */ |
| 400 | struct pll_fields *plld; |
| 401 | u32 ref = clock_get_pll_input_khz() * 1000, m, n, p = 0; |
| 402 | u32 cf, vco, rounded_rate = frequency; |
| 403 | u32 diff, best_diff; |
| 404 | const u32 max_m = 1 << 8, max_n = 1 << 8, max_p = 1 << 3, |
| 405 | mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz, |
| 406 | min_cf = 1 * mhz, max_cf = 6 * mhz; |
| 407 | u32 osc = clock_get_osc_bits(); |
| 408 | |
| 409 | plld = &osc_table[osc].plls[PLLD_INDEX]; |
| 410 | |
| 411 | for (vco = frequency; vco < min_vco && p < max_p; p++) |
| 412 | vco <<= 1; |
| 413 | |
| 414 | if (vco < min_vco || vco > max_vco) { |
| 415 | printk(BIOS_ERR, "%s: Cannot find out a supported VCO" |
| 416 | " for Frequency (%u).\n", __func__, frequency); |
| 417 | return 0; |
| 418 | } |
| 419 | |
| 420 | plld->p = p; |
| 421 | best_diff = vco; |
| 422 | |
| 423 | for (m = 1; m < max_m && best_diff; m++) { |
| 424 | cf = ref / m; |
| 425 | if (cf < min_cf) |
| 426 | break; |
| 427 | if (cf > max_cf) |
| 428 | continue; |
| 429 | |
| 430 | n = vco / cf; |
| 431 | if (n >= max_n) |
| 432 | continue; |
| 433 | |
| 434 | diff = vco - n * cf; |
| 435 | if (n + 1 < max_n && diff > cf / 2) { |
| 436 | n++; |
| 437 | diff = cf - diff; |
| 438 | } |
| 439 | |
| 440 | if (diff >= best_diff) |
| 441 | continue; |
| 442 | |
| 443 | best_diff = diff; |
| 444 | plld->m = m; |
| 445 | plld->n = n; |
| 446 | } |
| 447 | |
| 448 | if (best_diff) { |
| 449 | printk(BIOS_WARNING, "%s: Failed to match output frequency %u, " |
| 450 | "best difference is %u.\n", __func__, frequency, |
| 451 | best_diff); |
| 452 | rounded_rate = (ref / plld->m * plld->n) >> plld->p; |
| 453 | } |
| 454 | |
| 455 | printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p=%u/%u/%u\n", |
| 456 | __func__, rounded_rate, ref, plld->m, plld->n, plld->p); |
| 457 | |
| 458 | /* Write misc1 and misc */ |
| 459 | write32(CLK_RST_REG(plld_misc1), PLLD_MISC1_SETUP); |
| 460 | write32(CLK_RST_REG(plld_misc), (PLLD_MISC_EN_SDM | PLLD_MISC_SDM_DIN)); |
| 461 | |
| 462 | /* configure PLLD */ |
| 463 | init_pll(PLLD_INDEX, osc); |
| 464 | |
| 465 | if (rounded_rate != frequency) |
| 466 | printk(BIOS_DEBUG, "PLLD rate: %u vs %u\n", rounded_rate, |
| 467 | frequency); |
| 468 | |
| 469 | return rounded_rate; |
| 470 | } |
| 471 | |
| 472 | /* |
| 473 | * Initialize the UART and use PLLP as clock source. PLLP is hardwired to 408 |
| 474 | * MHz in HW (unless we set BASE_OVRD). We override the 16.0 UART divider with |
| 475 | * the 15.1 CLK_SOURCE divider to get more precision. The 1843(KHZ) is |
| 476 | * calculated thru BAUD_RATE*16/1000, ie, 115200*16/1000. |
| 477 | */ |
| 478 | void clock_early_uart(void) |
| 479 | { |
Andre Heider | 92712d3 | 2018-02-16 12:44:11 +0100 | [diff] [blame] | 480 | if (console_uart_get_id() == UART_ID_NONE) |
| 481 | return; |
| 482 | |
| 483 | write32(console_uart_clk_rst_reg(), |
| 484 | console_uart_clk_src_dev_id() << CLK_SOURCE_SHIFT | |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 485 | CLK_UART_DIV_OVERRIDE | |
| 486 | CLK_DIVIDER(TEGRA_PLLP_KHZ, 1843)); |
| 487 | |
Andre Heider | 92712d3 | 2018-02-16 12:44:11 +0100 | [diff] [blame] | 488 | console_uart_clock_enable_clear_reset(); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 489 | } |
| 490 | |
| 491 | /* Enable output clock (CLK1~3) for external peripherals. */ |
| 492 | void clock_external_output(int clk_id) |
| 493 | { |
| 494 | switch (clk_id) { |
| 495 | case 1: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 496 | setbits32(&pmc->clk_out_cntrl, 1 << 2); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 497 | break; |
| 498 | case 2: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 499 | setbits32(&pmc->clk_out_cntrl, 1 << 10); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 500 | break; |
| 501 | case 3: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 502 | setbits32(&pmc->clk_out_cntrl, 1 << 18); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 503 | break; |
| 504 | default: |
| 505 | printk(BIOS_CRIT, "ERROR: Unknown output clock id %d\n", |
| 506 | clk_id); |
| 507 | break; |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | /* Start PLLM for SDRAM. */ |
| 512 | void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 kvco, u32 kcp, |
| 513 | u32 stable_time, u32 emc_source, u32 same_freq) |
| 514 | { |
| 515 | u32 misc1 = ((setup << PLLM_MISC1_SETUP_SHIFT)), |
| 516 | misc2 = ((kvco << PLLM_MISC2_KVCO_SHIFT) | |
| 517 | (kcp << PLLM_MISC2_KCP_SHIFT) | |
| 518 | PLLM_EN_LCKDET), |
| 519 | base; |
| 520 | |
| 521 | if (same_freq) |
| 522 | emc_source |= CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; |
| 523 | else |
| 524 | emc_source &= ~CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; |
| 525 | |
| 526 | /* |
| 527 | * Note PLLM_BASE.PLLM_OUT1_RSTN must be in RESET_ENABLE mode, and |
| 528 | * PLLM_BASE.ENABLE must be in DISABLE state (both are the default |
| 529 | * values after coldboot reset). |
| 530 | */ |
| 531 | |
| 532 | write32(CLK_RST_REG(pllm_misc1), misc1); |
| 533 | write32(CLK_RST_REG(pllm_misc2), misc2); |
| 534 | |
| 535 | /* PLLM.BASE needs BYPASS=0, different from general init_pll */ |
| 536 | base = read32(CLK_RST_REG(pllm_base)); |
| 537 | base &= ~(PLLCMX_BASE_DIVN_MASK | PLLCMX_BASE_DIVM_MASK | |
| 538 | PLLM_BASE_DIVP_MASK | PLL_BASE_BYPASS); |
| 539 | base |= ((m << PLL_BASE_DIVM_SHIFT) | (n << PLL_BASE_DIVN_SHIFT) | |
| 540 | (p << PLL_BASE_DIVP_SHIFT)); |
| 541 | write32(CLK_RST_REG(pllm_base), base); |
| 542 | |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 543 | setbits32(CLK_RST_REG(pllm_base), PLL_BASE_ENABLE); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 544 | /* stable_time is required, before we can start to check lock. */ |
| 545 | udelay(stable_time); |
| 546 | |
| 547 | while (!(read32(CLK_RST_REG(pllm_base)) & PLL_BASE_LOCK)) |
| 548 | udelay(1); |
| 549 | |
| 550 | /* |
| 551 | * After PLLM reports being locked, we have to delay 10us before |
| 552 | * enabling PLLM_OUT. |
| 553 | */ |
| 554 | udelay(10); |
| 555 | |
| 556 | /* Enable and start MEM(MC) and EMC. */ |
| 557 | clock_enable_clear_reset(0, CLK_H_MEM | CLK_H_EMC, 0, 0, 0, 0, 0); |
| 558 | write32(CLK_RST_REG(clk_src_emc), emc_source); |
| 559 | udelay(IO_STABILIZATION_DELAY); |
| 560 | } |
| 561 | |
| 562 | void clock_halt_avp(void) |
| 563 | { |
| 564 | for (;;) { |
| 565 | write32(&flow->halt_cop_events, |
| 566 | FLOW_EVENT_JTAG | FLOW_EVENT_LIC_IRQ | |
| 567 | FLOW_EVENT_GIC_IRQ | FLOW_MODE_WAITEVENT); |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | void clock_init(void) |
| 572 | { |
| 573 | u32 osc = clock_get_osc_bits(); |
| 574 | /* clk_m = osc/2 */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 575 | clrsetbits32(CLK_RST_REG(spare_reg0), CLK_M_DIVISOR_MASK, |
| 576 | CLK_M_DIVISOR_BY_2); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 577 | |
| 578 | /* TIMERUS needs to be adjusted for new 19.2MHz CLK_M rate */ |
| 579 | write32((void *)TEGRA_TMRUS_BASE + TIMERUS_USEC_CFG, |
| 580 | TIMERUS_USEC_CFG_19P2_CLK_M); |
| 581 | |
| 582 | init_pllc(osc); |
| 583 | |
| 584 | /* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA |
| 585 | * features section in the TRM). */ |
| 586 | write32(CLK_RST_REG(clk_sys_rate), /* pclk = hclk = sclk/2 */ |
| 587 | 1 << HCLK_DIVISOR_SHIFT | 0 << PCLK_DIVISOR_SHIFT); |
| 588 | write32(CLK_RST_REG(pllc_out), |
| 589 | CLK_DIVIDER(TEGRA_PLLC_KHZ, 300000) << PLL_OUT_RATIO_SHIFT | |
| 590 | PLL_OUT_CLKEN | PLL_OUT_RSTN); |
| 591 | write32(CLK_RST_REG(sclk_brst_pol), /* sclk = 300 MHz */ |
| 592 | SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT | |
| 593 | SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT); |
| 594 | |
| 595 | /* Change the oscillator drive strength (from U-Boot -- why?) */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 596 | clrsetbits32(CLK_RST_REG(osc_ctrl), OSC_XOFS_MASK, |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 597 | OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT); |
| 598 | |
| 599 | /* |
| 600 | * Ambiguous quote from u-boot. TODO: what's this mean? |
| 601 | * "should update same value in PMC_OSC_EDPD_OVER XOFS |
| 602 | * field for warmboot " |
| 603 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 604 | clrsetbits32(&pmc->osc_edpd_over, PMC_OSC_EDPD_OVER_XOFS_MASK, |
| 605 | OSC_DRIVE_STRENGTH << PMC_OSC_EDPD_OVER_XOFS_SHIFT); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 606 | |
| 607 | /* Disable IDDQ for PLLX before we set it up (from U-Boot -- why?) */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 608 | clrbits32(CLK_RST_REG(pllx_misc3), PLLX_IDDQ_MASK); |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 609 | |
| 610 | /* Set up PLLP_OUT(1|2|3|4) divisor to generate (9.6|48|102|204)MHz */ |
| 611 | write32(CLK_RST_REG(pllp_outa), |
| 612 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 9600) << PLL_OUT_RATIO_SHIFT | |
| 613 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT1_SHIFT | |
| 614 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000) << PLL_OUT_RATIO_SHIFT | |
| 615 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT2_SHIFT); |
| 616 | write32(CLK_RST_REG(pllp_outb), |
| 617 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, TEGRA_PLLP_OUT3_KHZ) << |
| 618 | PLL_OUT_RATIO_SHIFT | |
| 619 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT3_SHIFT | |
| 620 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 204000) << PLL_OUT_RATIO_SHIFT | |
| 621 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT4_SHIFT); |
| 622 | |
| 623 | /* init pllx */ |
| 624 | init_pll(PLLX_INDEX, osc); |
| 625 | write32(CLK_RST_REG(cclk_brst_pol), CCLK_BURST_POLICY_VAL); |
| 626 | |
| 627 | /* init pllu */ |
| 628 | init_pllu(osc); |
| 629 | |
| 630 | init_utmip_pll(); |
| 631 | graphics_pll(); |
| 632 | } |
| 633 | |
Elyes HAOUAS | 448d9fb | 2018-05-22 12:51:27 +0200 | [diff] [blame] | 634 | void clock_grp_enable_clear_reset(u32 val, u32 *clk_enb_set_reg, |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 635 | u32 *rst_dev_clr_reg) |
| 636 | { |
| 637 | write32(clk_enb_set_reg, val); |
| 638 | udelay(IO_STABILIZATION_DELAY); |
| 639 | write32(rst_dev_clr_reg, val); |
| 640 | } |
| 641 | |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 642 | static u32 *const clk_enb_set_arr[DEV_CONFIG_BLOCKS] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 643 | CLK_RST_REG(clk_enb_l_set), |
| 644 | CLK_RST_REG(clk_enb_h_set), |
| 645 | CLK_RST_REG(clk_enb_u_set), |
| 646 | CLK_RST_REG(clk_enb_v_set), |
| 647 | CLK_RST_REG(clk_enb_w_set), |
| 648 | CLK_RST_REG(clk_enb_x_set), |
| 649 | CLK_RST_REG(clk_enb_y_set), |
| 650 | }; |
| 651 | |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 652 | static u32 *const clk_enb_clr_arr[DEV_CONFIG_BLOCKS] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 653 | CLK_RST_REG(clk_enb_l_clr), |
| 654 | CLK_RST_REG(clk_enb_h_clr), |
| 655 | CLK_RST_REG(clk_enb_u_clr), |
| 656 | CLK_RST_REG(clk_enb_v_clr), |
| 657 | CLK_RST_REG(clk_enb_w_clr), |
| 658 | CLK_RST_REG(clk_enb_x_clr), |
| 659 | CLK_RST_REG(clk_enb_y_clr), |
| 660 | }; |
| 661 | |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 662 | static u32 *const rst_dev_set_arr[DEV_CONFIG_BLOCKS] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 663 | CLK_RST_REG(rst_dev_l_set), |
| 664 | CLK_RST_REG(rst_dev_h_set), |
| 665 | CLK_RST_REG(rst_dev_u_set), |
| 666 | CLK_RST_REG(rst_dev_v_set), |
| 667 | CLK_RST_REG(rst_dev_w_set), |
| 668 | CLK_RST_REG(rst_dev_x_set), |
| 669 | CLK_RST_REG(rst_dev_y_set), |
| 670 | }; |
| 671 | |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 672 | static u32 *const rst_dev_clr_arr[DEV_CONFIG_BLOCKS] = { |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 673 | CLK_RST_REG(rst_dev_l_clr), |
| 674 | CLK_RST_REG(rst_dev_h_clr), |
| 675 | CLK_RST_REG(rst_dev_u_clr), |
| 676 | CLK_RST_REG(rst_dev_v_clr), |
| 677 | CLK_RST_REG(rst_dev_w_clr), |
| 678 | CLK_RST_REG(rst_dev_x_clr), |
| 679 | CLK_RST_REG(rst_dev_y_clr), |
| 680 | }; |
| 681 | |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 682 | static void clock_write_regs(u32 *const regs[DEV_CONFIG_BLOCKS], |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 683 | u32 bits[DEV_CONFIG_BLOCKS]) |
| 684 | { |
| 685 | int i = 0; |
| 686 | |
| 687 | for (; i < DEV_CONFIG_BLOCKS; i++) |
| 688 | if (bits[i]) |
| 689 | write32(regs[i], bits[i]); |
| 690 | } |
| 691 | |
| 692 | void clock_enable_regs(u32 bits[DEV_CONFIG_BLOCKS]) |
| 693 | { |
| 694 | clock_write_regs(clk_enb_set_arr, bits); |
| 695 | } |
| 696 | |
| 697 | void clock_disable_regs(u32 bits[DEV_CONFIG_BLOCKS]) |
| 698 | { |
| 699 | clock_write_regs(clk_enb_clr_arr, bits); |
| 700 | } |
| 701 | |
| 702 | void clock_set_reset_regs(u32 bits[DEV_CONFIG_BLOCKS]) |
| 703 | { |
| 704 | clock_write_regs(rst_dev_set_arr, bits); |
| 705 | } |
| 706 | |
| 707 | void clock_clr_reset_regs(u32 bits[DEV_CONFIG_BLOCKS]) |
| 708 | { |
| 709 | clock_write_regs(rst_dev_clr_arr, bits); |
| 710 | } |
| 711 | |
| 712 | void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x, u32 y) |
| 713 | { |
| 714 | clock_enable(l, h, u, v, w, x, y); |
| 715 | |
| 716 | /* Give clocks time to stabilize. */ |
| 717 | udelay(IO_STABILIZATION_DELAY); |
| 718 | |
| 719 | clock_clr_reset(l, h, u, v, w, x, y); |
| 720 | } |
| 721 | |
| 722 | static void clock_reset_dev(u32 *setaddr, u32 *clraddr, u32 bit) |
| 723 | { |
| 724 | write32(setaddr, bit); |
| 725 | udelay(LOGIC_STABILIZATION_DELAY); |
| 726 | write32(clraddr, bit); |
| 727 | } |
| 728 | |
| 729 | void clock_reset_l(u32 bit) |
| 730 | { |
| 731 | clock_reset_dev(CLK_RST_REG(rst_dev_l_set), CLK_RST_REG(rst_dev_l_clr), |
| 732 | bit); |
| 733 | } |
| 734 | |
| 735 | void clock_reset_h(u32 bit) |
| 736 | { |
| 737 | clock_reset_dev(CLK_RST_REG(rst_dev_h_set), CLK_RST_REG(rst_dev_h_clr), |
| 738 | bit); |
| 739 | } |
| 740 | |
| 741 | void clock_reset_u(u32 bit) |
| 742 | { |
| 743 | clock_reset_dev(CLK_RST_REG(rst_dev_u_set), CLK_RST_REG(rst_dev_u_clr), |
| 744 | bit); |
| 745 | } |
| 746 | |
| 747 | void clock_reset_v(u32 bit) |
| 748 | { |
| 749 | clock_reset_dev(CLK_RST_REG(rst_dev_v_set), CLK_RST_REG(rst_dev_v_clr), |
| 750 | bit); |
| 751 | } |
| 752 | |
| 753 | void clock_reset_w(u32 bit) |
| 754 | { |
| 755 | clock_reset_dev(CLK_RST_REG(rst_dev_w_set), CLK_RST_REG(rst_dev_w_clr), |
| 756 | bit); |
| 757 | } |
| 758 | |
| 759 | void clock_reset_x(u32 bit) |
| 760 | { |
| 761 | clock_reset_dev(CLK_RST_REG(rst_dev_x_set), CLK_RST_REG(rst_dev_x_clr), |
| 762 | bit); |
| 763 | } |
| 764 | |
| 765 | void clock_reset_y(u32 bit) |
| 766 | { |
| 767 | clock_reset_dev(CLK_RST_REG(rst_dev_y_set), CLK_RST_REG(rst_dev_y_clr), |
| 768 | bit); |
| 769 | } |
| 770 | |
| 771 | /* Enable/unreset all audio toys under AHUB */ |
| 772 | void clock_enable_audio(void) |
| 773 | { |
| 774 | /* |
| 775 | * As per NVIDIA hardware team, we need to take ALL audio devices |
| 776 | * connected to AHUB (AHUB, APB2APE, I2S, SPDIF, etc.) out of reset |
| 777 | * and clock-enabled, otherwise reading AHUB devices (in our case, |
| 778 | * I2S/APBIF/AUDIO<XBAR>) will hang. |
| 779 | */ |
| 780 | clock_enable_clear_reset(CLK_L_I2S1 | CLK_L_I2S2 | CLK_L_I2S3 | CLK_L_SPDIF, |
| 781 | 0, 0, |
Yen Lin | ff40196 | 2015-07-14 11:20:08 -0700 | [diff] [blame] | 782 | CLK_V_I2S4 | CLK_V_I2S5 | CLK_V_AHUB | CLK_V_APB2APE | |
| 783 | CLK_V_EXTPERIPH1, |
Patrick Georgi | 40a3e32 | 2015-06-22 19:41:29 +0200 | [diff] [blame] | 784 | 0, 0, 0); |
| 785 | } |