Angel Pons | a2ee761 | 2020-04-04 18:51:15 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Angel Pons | a2ee761 | 2020-04-04 18:51:15 +0200 | [diff] [blame] | 2 | |
Jacob Garber | 693c55c | 2019-07-25 12:06:28 -0600 | [diff] [blame] | 3 | #include <assert.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 4 | #include <arch/clock.h> |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 5 | #include <device/mmio.h> |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 6 | #include <console/console.h> |
Ronald G. Minnich | 3eab7ed | 2013-10-03 17:05:55 -0700 | [diff] [blame] | 7 | #include <delay.h> |
Gabe Black | e97b683 | 2013-10-06 06:13:24 -0700 | [diff] [blame] | 8 | #include <soc/addressmap.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 9 | #include <soc/clk_rst.h> |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 10 | #include <soc/clock.h> |
Julius Werner | f0d21ff3 | 2014-10-20 13:24:14 -0700 | [diff] [blame] | 11 | #include <soc/flow.h> |
| 12 | #include <soc/maincpu.h> |
| 13 | #include <soc/pmc.h> |
| 14 | #include <soc/sysctr.h> |
Julius Werner | ec5e5e0 | 2014-08-20 15:29:56 -0700 | [diff] [blame] | 15 | #include <symbols.h> |
Gabe Black | e97b683 | 2013-10-06 06:13:24 -0700 | [diff] [blame] | 16 | |
| 17 | static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 18 | static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE; |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 19 | static struct tegra_pmc_regs *pmc = (void *)TEGRA_PMC_BASE; |
| 20 | static struct sysctr_regs *sysctr = (void *)TEGRA_SYSCTR0_BASE; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 21 | |
| 22 | struct pll_dividers { |
| 23 | u32 n : 10; |
| 24 | u32 m : 8; |
| 25 | u32 p : 4; |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 26 | u32 cpcon : 4; |
| 27 | u32 lfcon : 4; |
| 28 | u32 : 2; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 29 | }; |
| 30 | |
| 31 | /* Some PLLs have more restrictive divider bit lengths or are missing some |
| 32 | * fields. Make sure to use the right struct in the osc_table definition to get |
| 33 | * compile-time checking, but keep the bits aligned with struct pll_dividers so |
| 34 | * they can be used interchangeably at run time. Add new formats as required. */ |
| 35 | struct pllcx_dividers { |
| 36 | u32 n : 8; |
| 37 | u32 : 2; |
| 38 | u32 m : 8; |
| 39 | u32 p : 4; |
| 40 | u32 : 10; |
| 41 | }; |
| 42 | struct pllpad_dividers { |
| 43 | u32 n : 10; |
| 44 | u32 m : 5; |
| 45 | u32 : 3; |
| 46 | u32 p : 3; |
| 47 | u32 : 1; |
| 48 | u32 cpcon : 4; |
| 49 | u32 : 6; |
| 50 | }; |
| 51 | struct pllu_dividers { |
| 52 | u32 n : 10; |
| 53 | u32 m : 5; |
| 54 | u32 : 3; |
| 55 | u32 p : 1; |
| 56 | u32 : 3; |
| 57 | u32 cpcon : 4; |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 58 | u32 lfcon : 4; |
| 59 | u32 : 2; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 60 | }; |
| 61 | |
| 62 | union __attribute__((transparent_union)) pll_fields { |
| 63 | u32 raw; |
| 64 | struct pll_dividers div; |
| 65 | struct pllcx_dividers cx; |
| 66 | struct pllpad_dividers pad; |
| 67 | struct pllu_dividers u; |
| 68 | }; |
| 69 | |
| 70 | /* This table defines the frequency dividers for every PLL to turn the external |
| 71 | * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h. |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 72 | * All PLLs have three dividers (n, m and p), with the governing formula for |
| 73 | * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p). |
| 74 | * All divisor configurations must meet the PLL's constraints for VCO and CF: |
| 75 | * PLLX: 12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz |
| 76 | * PLLC: 12 MHz < CF < 50 MHz, 600 MHz < VCO < 1400 MHz |
| 77 | * PLLM: 12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz |
| 78 | * PLLP: 1 MHz < CF < 6 MHz, 200 MHz < VCO < 700 MHz |
| 79 | * PLLD: 1 MHz < CF < 6 MHz, 500 MHz < VCO < 1000 MHz |
| 80 | * PLLU: 1 MHz < CF < 6 MHz, 480 MHz < VCO < 960 MHz |
| 81 | * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz |
| 82 | * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c). */ |
Felix Singer | d74ee60 | 2024-01-09 00:19:19 +0100 | [diff] [blame] | 83 | static const struct { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 84 | int khz; |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 85 | struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 86 | struct pllcx_dividers pllc; /* target: 600 MHz */ |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 87 | /* PLLM is set up dynamically by clock_sdram(). */ |
| 88 | /* PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD). */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 89 | struct pllu_dividers pllu; /* target; 960 MHz */ |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 90 | struct pllcx_dividers plldp; /* target; 270 MHz */ |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 91 | /* PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6). */ |
Felix Singer | d74ee60 | 2024-01-09 00:19:19 +0100 | [diff] [blame] | 92 | } osc_table[16] = { |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 93 | [OSC_FREQ_12] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 94 | .khz = 12000, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 95 | .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 96 | .pllc = {.n = 50, .m = 1, .p = 0}, |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 97 | .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 98 | .plldp = {.n = 90, .m = 1, .p = 3}, |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 99 | }, |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 100 | [OSC_FREQ_13] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 101 | .khz = 13000, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 102 | .pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 103 | .pllc = {.n = 46, .m = 1, .p = 0}, /* 598.0 MHz */ |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 104 | .pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 105 | .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.8 MHz */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 106 | }, |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 107 | [OSC_FREQ_16P8] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 108 | .khz = 16800, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 109 | .pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 110 | .pllc = {.n = 71, .m = 1, .p = 1}, /* 596.4 MHz */ |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 111 | .pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 5, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 112 | .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 113 | }, |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 114 | [OSC_FREQ_19P2] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 115 | .khz = 19200, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 116 | .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 117 | .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 118 | .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 119 | .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 120 | }, |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 121 | [OSC_FREQ_26] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 122 | .khz = 26000, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 123 | .pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 124 | .pllc = {.n = 23, .m = 1, .p = 0}, /* 598.0 MHz */ |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 125 | .pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 126 | .plldp = {.n = 83, .m = 2, .p = 3}, /* 269.8 MHz */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 127 | }, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 128 | /* These oscillators get predivided as PLL inputs... n/m/p divisors for |
| 129 | * 38.4 should always match 19.2, and 48 should always match 12. */ |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 130 | [OSC_FREQ_38P4] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 131 | .khz = 38400, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 132 | .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 133 | .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 134 | .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 135 | .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 136 | }, |
Arthur Heymans | 961e09c | 2022-03-24 00:11:07 +0100 | [diff] [blame] | 137 | [OSC_FREQ_48] = { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 138 | .khz = 48000, |
Gabe Black | 3178503 | 2014-03-03 16:26:11 -0800 | [diff] [blame] | 139 | .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 140 | .pllc = {.n = 50, .m = 1, .p = 0}, |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 141 | .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 142 | .plldp = {.n = 90, .m = 1, .p = 3}, |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 143 | }, |
| 144 | }; |
| 145 | |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 146 | /* Get the oscillator frequency, from the corresponding hardware |
| 147 | * configuration field. This is actually a per-soc thing. Avoid the |
| 148 | * temptation to make it common. |
Ronald G. Minnich | 3eab7ed | 2013-10-03 17:05:55 -0700 | [diff] [blame] | 149 | */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 150 | static u32 clock_get_osc_bits(void) |
| 151 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 152 | return (read32(&clk_rst->osc_ctrl) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | int clock_get_osc_khz(void) |
| 156 | { |
| 157 | return osc_table[clock_get_osc_bits()].khz; |
| 158 | } |
| 159 | |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 160 | int clock_get_pll_input_khz(void) |
| 161 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 162 | u32 osc_ctrl = read32(&clk_rst->osc_ctrl); |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 163 | u32 osc_bits = (osc_ctrl & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; |
| 164 | u32 pll_ref_div = (osc_ctrl & OSC_PREDIV_MASK) >> OSC_PREDIV_SHIFT; |
| 165 | return osc_table[osc_bits].khz >> pll_ref_div; |
| 166 | } |
| 167 | |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 168 | void clock_init_arm_generic_timer(void) |
| 169 | { |
| 170 | uint32_t freq = clock_get_osc_khz() * 1000; |
| 171 | // Set the cntfrq register. |
Furquan Shaikh | d653ae8 | 2014-06-24 15:21:03 -0700 | [diff] [blame] | 172 | set_cntfrq(freq); |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 173 | |
| 174 | // Record the system timer frequency. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 175 | write32(&sysctr->cntfid0, freq); |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 176 | // Enable the system counter. |
| 177 | uint32_t cntcr = read32(&sysctr->cntcr); |
| 178 | cntcr |= SYSCTR_CNTCR_EN | SYSCTR_CNTCR_HDBG; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 179 | write32(&sysctr->cntcr, cntcr); |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 180 | } |
| 181 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 182 | #define SOR0_CLK_SEL0 (1 << 14) |
| 183 | #define SOR0_CLK_SEL1 (1 << 15) |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 184 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 185 | void sor_clock_stop(void) |
| 186 | { |
| 187 | /* The Serial Output Resource clock has to be off |
| 188 | * before we start the plldp. Learned the hard way. |
| 189 | * FIXME: this has to be cleaned up a bit more. |
| 190 | * Waiting on some new info from Nvidia. |
| 191 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 192 | clrbits32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0 | SOR0_CLK_SEL1); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | void sor_clock_start(void) |
| 196 | { |
| 197 | /* uses PLLP, has a non-standard bit layout. */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 198 | setbits32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 199 | } |
| 200 | |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 201 | static void init_pll(u32 *base, u32 *misc, const union pll_fields pll, u32 lock) |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 202 | { |
| 203 | u32 dividers = pll.div.n << PLL_BASE_DIVN_SHIFT | |
| 204 | pll.div.m << PLL_BASE_DIVM_SHIFT | |
| 205 | pll.div.p << PLL_BASE_DIVP_SHIFT; |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 206 | u32 misc_con = pll.div.cpcon << PLL_MISC_CPCON_SHIFT | |
| 207 | pll.div.lfcon << PLL_MISC_LFCON_SHIFT; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 208 | |
| 209 | /* Write dividers but BYPASS the PLL while we're messing with it. */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 210 | write32(base, dividers | PLL_BASE_BYPASS); |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 211 | /* |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 212 | * Set Lock bit, CPCON and LFCON fields (default to 0 if it doesn't |
| 213 | * exist for this PLL) |
Andrew Bresticker | 25bf775 | 2014-03-04 11:06:13 -0800 | [diff] [blame] | 214 | */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 215 | write32(misc, lock | misc_con); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 216 | |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 217 | /* Enable PLL and take it back out of BYPASS */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 218 | write32(base, dividers | PLL_BASE_ENABLE); |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 219 | |
| 220 | /* Wait for lock ready */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 221 | while (!(read32(base) & PLL_BASE_LOCK)); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 222 | } |
| 223 | |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 224 | static void init_utmip_pll(void) |
| 225 | { |
Julius Werner | e57c303 | 2014-04-11 18:23:12 -0700 | [diff] [blame] | 226 | int khz = clock_get_pll_input_khz(); |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 227 | |
| 228 | /* Shut off PLL crystal clock while we mess with it */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 229 | clrbits32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */ |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 230 | udelay(1); |
| 231 | |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 232 | write32(&clk_rst->utmip_pll_cfg0, /* 960MHz * 1 / 80 == 12 MHz */ |
| 233 | 80 << 16 | /* (rst) phy_divn */ |
| 234 | 1 << 8); /* (rst) phy_divm */ |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 235 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 236 | write32(&clk_rst->utmip_pll_cfg1, |
Elyes HAOUAS | 6df3b64 | 2018-11-26 22:53:49 +0100 | [diff] [blame] | 237 | DIV_ROUND_UP(khz, 8000) << 27 | /* pllu_enbl_cnt / 8 (1us) */ |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 238 | 0 << 16 | /* PLLU pwrdn */ |
| 239 | 0 << 14 | /* pll_enable pwrdn */ |
| 240 | 0 << 12 | /* pll_active pwrdn */ |
Elyes HAOUAS | 6df3b64 | 2018-11-26 22:53:49 +0100 | [diff] [blame] | 241 | DIV_ROUND_UP(khz, 102) << 0); /* phy_stbl_cnt / 256 (2.5ms) */ |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 242 | |
| 243 | /* TODO: TRM can't decide if actv is 5us or 10us, keep an eye on it */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 244 | write32(&clk_rst->utmip_pll_cfg2, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 245 | 0 << 24 | /* SAMP_D/XDEV pwrdn */ |
Elyes HAOUAS | 6df3b64 | 2018-11-26 22:53:49 +0100 | [diff] [blame] | 246 | DIV_ROUND_UP(khz, 3200) << 18 | /* phy_actv_cnt / 16 (5us) */ |
| 247 | DIV_ROUND_UP(khz, 256) << 6 | /* pllu_stbl_cnt / 256 (1ms) */ |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 248 | 0 << 4 | /* SAMP_C/USB3 pwrdn */ |
| 249 | 0 << 2 | /* SAMP_B/XHOST pwrdn */ |
| 250 | 0 << 0); /* SAMP_A/USBD pwrdn */ |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 251 | |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 252 | setbits32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */ |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 253 | } |
| 254 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 255 | /* Graphics just has to be different. There's a few more bits we |
| 256 | * need to set in here, but it makes sense just to restrict all the |
| 257 | * special bits to this one function. |
| 258 | */ |
| 259 | static void graphics_pll(void) |
| 260 | { |
| 261 | int osc = clock_get_osc_bits(); |
| 262 | u32 *cfg = &clk_rst->plldp_ss_cfg; |
| 263 | /* the vendor code sets the dither bit (28) |
| 264 | * an undocumented bit (24) |
| 265 | * and clamp while we mess with it (22) |
| 266 | * Dither is pretty important to display port |
| 267 | * so we really do need to handle these bits. |
| 268 | * I'm not willing to not clamp it, even if |
| 269 | * it might "mostly work" with it not set, |
| 270 | * I don't want to find out in a few months |
| 271 | * that it is needed. |
| 272 | */ |
| 273 | u32 scfg = (1<<28) | (1<<24) | (1<<22); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 274 | write32(cfg, scfg); |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 275 | init_pll(&clk_rst->plldp_base, &clk_rst->plldp_misc, |
| 276 | osc_table[osc].plldp, PLLDPD2_MISC_LOCK_ENABLE); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 277 | /* leave dither and undoc bits set, release clamp */ |
| 278 | scfg = (1<<28) | (1<<24); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 279 | write32(cfg, scfg); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 280 | |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 281 | /* disp1 will be set when panel information (pixel clock) is |
| 282 | * retrieved (clock_display). |
| 283 | */ |
| 284 | } |
| 285 | |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 286 | /* |
| 287 | * Init PLLD clock source. |
| 288 | * |
| 289 | * @frequency: the requested plld frequency |
| 290 | * |
| 291 | * Return the plld frequency if success, otherwise return 0. |
| 292 | */ |
| 293 | u32 |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 294 | clock_display(u32 frequency) |
| 295 | { |
| 296 | /** |
| 297 | * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz |
| 298 | * = (cf * n) >> p, where 1MHz < cf < 6MHz |
| 299 | * = ((ref / m) * n) >> p |
| 300 | * |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 301 | * Iterate the possible values of p (3 bits, 2^7) to find out a minimum |
| 302 | * safe vco, then find best (m, n). since m has only 5 bits, we can |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 303 | * iterate all possible values. Note Tegra 124 supports 11 bits for n, |
| 304 | * but our pll_fields has only 10 bits for n. |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 305 | * |
| 306 | * Note values undershoot or overshoot target output frequency may not |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 307 | * work if the values are not in "safe" range by panel specification. |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 308 | */ |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 309 | struct pllpad_dividers plld = { 0 }; |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 310 | u32 ref = clock_get_pll_input_khz() * 1000, m, n, p = 0; |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 311 | u32 cf, vco, rounded_rate = frequency; |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 312 | u32 diff, best_diff; |
| 313 | const u32 max_m = 1 << 5, max_n = 1 << 10, max_p = 1 << 3, |
| 314 | mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz, |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 315 | min_cf = 1 * mhz, max_cf = 6 * mhz; |
| 316 | |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 317 | for (vco = frequency; vco < min_vco && p < max_p; p++) |
| 318 | vco <<= 1; |
| 319 | |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 320 | if (vco < min_vco || vco > max_vco) { |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 321 | printk(BIOS_ERR, "%s: Cannot find out a supported VCO" |
| 322 | " for Frequency (%u).\n", __func__, frequency); |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 323 | return 0; |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 324 | } |
| 325 | |
Ken Chang | cbae0de | 2014-04-18 13:52:48 +0800 | [diff] [blame] | 326 | plld.p = p; |
| 327 | best_diff = vco; |
| 328 | |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 329 | for (m = 1; m < max_m && best_diff; m++) { |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 330 | cf = ref / m; |
| 331 | if (cf < min_cf) |
| 332 | break; |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 333 | if (cf > max_cf) |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 334 | continue; |
| 335 | |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 336 | n = vco / cf; |
| 337 | if (n >= max_n) |
| 338 | continue; |
| 339 | |
| 340 | diff = vco - n * cf; |
| 341 | if (n + 1 < max_n && diff > cf / 2) { |
| 342 | n++; |
| 343 | diff = cf - diff; |
| 344 | } |
| 345 | |
| 346 | if (diff >= best_diff) |
| 347 | continue; |
| 348 | |
| 349 | best_diff = diff; |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 350 | plld.m = m; |
| 351 | plld.n = n; |
Hung-Te Lin | 1a8e0af | 2014-04-08 20:03:40 +0800 | [diff] [blame] | 352 | } |
| 353 | |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 354 | if (plld.n < 50) |
| 355 | plld.cpcon = 2; |
| 356 | else if (plld.n < 300) |
| 357 | plld.cpcon = 3; |
| 358 | else if (plld.n < 600) |
| 359 | plld.cpcon = 8; |
| 360 | else |
| 361 | plld.cpcon = 12; |
| 362 | |
| 363 | if (best_diff) { |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 364 | printk(BIOS_WARNING, "%s: Failed to match output frequency %u, " |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 365 | "best difference is %u.\n", __func__, frequency, |
| 366 | best_diff); |
Jacob Garber | 693c55c | 2019-07-25 12:06:28 -0600 | [diff] [blame] | 367 | assert(plld.m != 0); |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 368 | rounded_rate = (ref / plld.m * plld.n) >> plld.p; |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 369 | } |
| 370 | |
| 371 | printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p/cpcon=%u/%u/%u/%u\n", |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 372 | __func__, rounded_rate, ref, plld.m, plld.n, plld.p, plld.cpcon); |
Hung-Te Lin | 0cbba82 | 2014-04-17 08:20:04 +0800 | [diff] [blame] | 373 | |
| 374 | init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, plld, |
| 375 | (PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE)); |
Vince Hsu | 1e3679d | 2014-06-11 17:14:05 +0800 | [diff] [blame] | 376 | |
| 377 | return rounded_rate; |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 378 | } |
| 379 | |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 380 | /* Initialize the UART and put it on CLK_M so we can use it during clock_init(). |
| 381 | * Will later move it to PLLP in clock_config(). The divisor must be very small |
Martin Roth | 2ed0aa2 | 2016-01-05 20:58:58 -0700 | [diff] [blame] | 382 | * to accommodate 12KHz OSCs, so we override the 16.0 UART divider with the 15.1 |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 383 | * CLK_SOURCE divider to get more precision. (This might still not be enough for |
Gabe Black | e5b2127 | 2014-04-05 03:54:30 -0700 | [diff] [blame] | 384 | * some OSCs... if you use 13KHz, be prepared to have a bad time.) The 1900 has |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 385 | * been determined through trial and error (must lead to div 13 at 24MHz). */ |
| 386 | void clock_early_uart(void) |
| 387 | { |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 388 | write32(&clk_rst->clk_src_uarta, CLK_M << CLK_SOURCE_SHIFT | |
| 389 | CLK_UART_DIV_OVERRIDE | CLK_DIVIDER(TEGRA_CLK_M_KHZ, 1900)); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 390 | setbits32(&clk_rst->clk_out_enb_l, CLK_L_UARTA); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 391 | udelay(2); |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 392 | clrbits32(&clk_rst->rst_dev_l, CLK_L_UARTA); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 393 | } |
| 394 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 395 | /* Enable output clock (CLK1~3) for external peripherals. */ |
| 396 | void clock_external_output(int clk_id) |
| 397 | { |
| 398 | switch (clk_id) { |
| 399 | case 1: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 400 | setbits32(&pmc->clk_out_cntrl, 1 << 2); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 401 | break; |
| 402 | case 2: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 403 | setbits32(&pmc->clk_out_cntrl, 1 << 10); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 404 | break; |
| 405 | case 3: |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 406 | setbits32(&pmc->clk_out_cntrl, 1 << 18); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 407 | break; |
| 408 | default: |
| 409 | printk(BIOS_CRIT, "ERROR: Unknown output clock id %d\n", |
| 410 | clk_id); |
| 411 | break; |
| 412 | } |
| 413 | } |
| 414 | |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 415 | /* Start PLLM for SDRAM. */ |
| 416 | void clock_sdram(u32 m, u32 n, u32 p, u32 setup, u32 ph45, u32 ph90, |
| 417 | u32 ph135, u32 kvco, u32 kcp, u32 stable_time, u32 emc_source, |
| 418 | u32 same_freq) |
| 419 | { |
| 420 | u32 misc1 = ((setup << PLLM_MISC1_SETUP_SHIFT) | |
| 421 | (ph45 << PLLM_MISC1_PD_LSHIFT_PH45_SHIFT) | |
| 422 | (ph90 << PLLM_MISC1_PD_LSHIFT_PH90_SHIFT) | |
| 423 | (ph135 << PLLM_MISC1_PD_LSHIFT_PH135_SHIFT)), |
| 424 | misc2 = ((kvco << PLLM_MISC2_KVCO_SHIFT) | |
| 425 | (kcp << PLLM_MISC2_KCP_SHIFT)), |
| 426 | base; |
| 427 | |
| 428 | if (same_freq) |
| 429 | emc_source |= CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; |
| 430 | else |
| 431 | emc_source &= ~CLK_SOURCE_EMC_MC_EMC_SAME_FREQ; |
| 432 | |
| 433 | /* |
| 434 | * Note PLLM_BASE.PLLM_OUT1_RSTN must be in RESET_ENABLE mode, and |
| 435 | * PLLM_BASE.ENABLE must be in DISABLE state (both are the default |
| 436 | * values after coldboot reset). |
| 437 | */ |
| 438 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 439 | write32(&clk_rst->pllm_misc1, misc1); |
| 440 | write32(&clk_rst->pllm_misc2, misc2); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 441 | |
| 442 | /* PLLM.BASE needs BYPASS=0, different from general init_pll */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 443 | base = read32(&clk_rst->pllm_base); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 444 | base &= ~(PLLCMX_BASE_DIVN_MASK | PLLCMX_BASE_DIVM_MASK | |
| 445 | PLLM_BASE_DIVP_MASK | PLL_BASE_BYPASS); |
| 446 | base |= ((m << PLL_BASE_DIVM_SHIFT) | (n << PLL_BASE_DIVN_SHIFT) | |
| 447 | (p << PLL_BASE_DIVP_SHIFT)); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 448 | write32(&clk_rst->pllm_base, base); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 449 | |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 450 | setbits32(&clk_rst->pllm_base, PLL_BASE_ENABLE); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 451 | /* stable_time is required, before we can start to check lock. */ |
| 452 | udelay(stable_time); |
| 453 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 454 | while (!(read32(&clk_rst->pllm_base) & PLL_BASE_LOCK)) { |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 455 | udelay(1); |
| 456 | } |
| 457 | /* |
| 458 | * After PLLM reports being locked, we have to delay 10us before |
| 459 | * enabling PLLM_OUT. |
| 460 | */ |
| 461 | udelay(10); |
| 462 | |
| 463 | /* Put OUT1 out of reset state (start to output). */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 464 | setbits32(&clk_rst->pllm_out, PLLM_OUT1_RSTN_RESET_DISABLE); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 465 | |
| 466 | /* Enable and start MEM(MC) and EMC. */ |
| 467 | clock_enable_clear_reset(0, CLK_H_MEM | CLK_H_EMC, 0, 0, 0, 0); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 468 | write32(&clk_rst->clk_src_emc, emc_source); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 469 | udelay(IO_STABILIZATION_DELAY); |
| 470 | } |
| 471 | |
Jimmy Zhang | b365530 | 2014-07-02 17:45:18 -0700 | [diff] [blame] | 472 | void clock_cpu0_config(void *entry) |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 473 | { |
Elyes HAOUAS | 39303d5 | 2018-07-08 12:40:45 +0200 | [diff] [blame] | 474 | void *const evp_cpu_reset = (uint8_t *)TEGRA_EVP_BASE + 0x100; |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 475 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 476 | write32(&maincpu_stack_pointer, (uintptr_t)_estack); |
| 477 | write32(&maincpu_entry_point, (uintptr_t)entry); |
| 478 | write32(evp_cpu_reset, (uintptr_t)&maincpu_setup); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 479 | |
| 480 | /* Set active CPU cluster to G */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 481 | clrbits32(&flow->cluster_control, 1); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 482 | |
| 483 | // Set up cclk_brst and divider. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 484 | write32(&clk_rst->cclk_brst_pol, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 485 | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 0) | |
| 486 | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 4) | |
| 487 | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 8) | |
| 488 | (CRC_CCLK_BRST_POL_PLLX_OUT0 << 12) | |
| 489 | (CRC_CCLK_BRST_POL_CPU_STATE_RUN << 28)); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 490 | write32(&clk_rst->super_cclk_div, |
| 491 | CRC_SUPER_CCLK_DIVIDER_SUPER_CDIV_ENB); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 492 | |
| 493 | // Enable the clocks for CPUs 0-3. |
| 494 | uint32_t cpu_cmplx_clr = read32(&clk_rst->clk_cpu_cmplx_clr); |
| 495 | cpu_cmplx_clr |= CRC_CLK_CLR_CPU0_STP | CRC_CLK_CLR_CPU1_STP | |
| 496 | CRC_CLK_CLR_CPU2_STP | CRC_CLK_CLR_CPU3_STP; |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 497 | write32(&clk_rst->clk_cpu_cmplx_clr, cpu_cmplx_clr); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 498 | |
| 499 | // Enable other CPU related clocks. |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 500 | setbits32(&clk_rst->clk_out_enb_l, CLK_L_CPU); |
| 501 | setbits32(&clk_rst->clk_out_enb_v, CLK_V_CPUG); |
| 502 | setbits32(&clk_rst->clk_out_enb_v, CLK_V_CPULP); |
Jimmy Zhang | b365530 | 2014-07-02 17:45:18 -0700 | [diff] [blame] | 503 | } |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 504 | |
Jimmy Zhang | b365530 | 2014-07-02 17:45:18 -0700 | [diff] [blame] | 505 | void clock_cpu0_remove_reset(void) |
| 506 | { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 507 | // Disable the reset on the non-CPU parts of the fast cluster. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 508 | write32(&clk_rst->rst_cpug_cmplx_clr, CRC_RST_CPUG_CLR_NONCPU); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 509 | // Disable the various resets on the CPUs. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 510 | write32(&clk_rst->rst_cpug_cmplx_clr, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 511 | CRC_RST_CPUG_CLR_CPU0 | CRC_RST_CPUG_CLR_CPU1 | |
| 512 | CRC_RST_CPUG_CLR_CPU2 | CRC_RST_CPUG_CLR_CPU3 | |
| 513 | CRC_RST_CPUG_CLR_DBG0 | CRC_RST_CPUG_CLR_DBG1 | |
| 514 | CRC_RST_CPUG_CLR_DBG2 | CRC_RST_CPUG_CLR_DBG3 | |
| 515 | CRC_RST_CPUG_CLR_CORE0 | CRC_RST_CPUG_CLR_CORE1 | |
| 516 | CRC_RST_CPUG_CLR_CORE2 | CRC_RST_CPUG_CLR_CORE3 | |
| 517 | CRC_RST_CPUG_CLR_CX0 | CRC_RST_CPUG_CLR_CX1 | |
| 518 | CRC_RST_CPUG_CLR_CX2 | CRC_RST_CPUG_CLR_CX3 | |
| 519 | CRC_RST_CPUG_CLR_L2 | CRC_RST_CPUG_CLR_PDBG); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 520 | |
| 521 | // Disable the reset on the non-CPU parts of the slow cluster. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 522 | write32(&clk_rst->rst_cpulp_cmplx_clr, CRC_RST_CPULP_CLR_NONCPU); |
Andrew Bresticker | 24d4f7f | 2013-12-18 22:41:34 -0800 | [diff] [blame] | 523 | // Disable the various resets on the LP CPU. |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 524 | write32(&clk_rst->rst_cpulp_cmplx_clr, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 525 | CRC_RST_CPULP_CLR_CPU0 | CRC_RST_CPULP_CLR_DBG0 | |
| 526 | CRC_RST_CPULP_CLR_CORE0 | CRC_RST_CPULP_CLR_CX0 | |
| 527 | CRC_RST_CPULP_CLR_L2 | CRC_RST_CPULP_CLR_PDBG); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 528 | } |
| 529 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 530 | void clock_halt_avp(void) |
| 531 | { |
| 532 | for (;;) { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 533 | write32(&flow->halt_cop_events, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 534 | FLOW_EVENT_JTAG | FLOW_EVENT_LIC_IRQ | |
| 535 | FLOW_EVENT_GIC_IRQ | FLOW_MODE_WAITEVENT); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 536 | } |
| 537 | } |
| 538 | |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 539 | void clock_init(void) |
Ronald G. Minnich | 3eab7ed | 2013-10-03 17:05:55 -0700 | [diff] [blame] | 540 | { |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 541 | u32 osc = clock_get_osc_bits(); |
Ronald G. Minnich | 3eab7ed | 2013-10-03 17:05:55 -0700 | [diff] [blame] | 542 | |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 543 | /* Set PLLC dynramp_step A to 0x2b and B to 0xb (from U-Boot -- why? */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 544 | write32(&clk_rst->pllc_misc2, 0x2b << 17 | 0xb << 9); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 545 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 546 | /* Max out the AVP clock before everything else (need PLLC for that). */ |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 547 | init_pll(&clk_rst->pllc_base, &clk_rst->pllc_misc, |
| 548 | osc_table[osc].pllc, PLLC_MISC_LOCK_ENABLE); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 549 | |
| 550 | /* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA |
| 551 | * features section in the TRM). */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 552 | write32(&clk_rst->clk_sys_rate, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 553 | TEGRA_HCLK_RATIO << HCLK_DIVISOR_SHIFT | |
| 554 | TEGRA_PCLK_RATIO << PCLK_DIVISOR_SHIFT); |
| 555 | write32(&clk_rst->pllc_out, CLK_DIVIDER(TEGRA_PLLC_KHZ, TEGRA_SCLK_KHZ) |
| 556 | << PLL_OUT_RATIO_SHIFT | PLL_OUT_CLKEN | PLL_OUT_RSTN); |
| 557 | write32(&clk_rst->sclk_brst_pol, /* sclk = 300 MHz */ |
| 558 | SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT | |
| 559 | SCLK_SOURCE_PLLC_OUT1 << SCLK_RUN_SHIFT); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 560 | |
| 561 | /* Change the oscillator drive strength (from U-Boot -- why?) */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 562 | clrsetbits32(&clk_rst->osc_ctrl, OSC_XOFS_MASK, |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 563 | OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT); |
| 564 | |
| 565 | /* |
| 566 | * Ambiguous quote from u-boot. TODO: what's this mean? |
| 567 | * "should update same value in PMC_OSC_EDPD_OVER XOFS |
| 568 | * field for warmboot " |
| 569 | */ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 570 | clrsetbits32(&pmc->osc_edpd_over, PMC_OSC_EDPD_OVER_XOFS_MASK, |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 571 | OSC_DRIVE_STRENGTH << PMC_OSC_EDPD_OVER_XOFS_SHIFT); |
| 572 | |
| 573 | /* 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] | 574 | clrbits32(&clk_rst->pllx_misc3, PLLX_IDDQ_MASK); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 575 | |
| 576 | /* Set up PLLP_OUT(1|2|3|4) divisor to generate (9.6|48|102|204)MHz */ |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 577 | write32(&clk_rst->pllp_outa, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 578 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 9600) << PLL_OUT_RATIO_SHIFT | |
| 579 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT1_SHIFT | |
| 580 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000) << PLL_OUT_RATIO_SHIFT | |
| 581 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT2_SHIFT); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 582 | write32(&clk_rst->pllp_outb, |
Julius Werner | 9418476 | 2015-02-19 20:19:23 -0800 | [diff] [blame] | 583 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 102000) << PLL_OUT_RATIO_SHIFT | |
| 584 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT3_SHIFT | |
| 585 | (CLK_DIVIDER(TEGRA_PLLP_KHZ, 204000) << PLL_OUT_RATIO_SHIFT | |
| 586 | PLL_OUT_OVR | PLL_OUT_CLKEN | PLL_OUT_RSTN) << PLL_OUT4_SHIFT); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 587 | |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 588 | /* init pllx */ |
| 589 | init_pll(&clk_rst->pllx_base, &clk_rst->pllx_misc, |
| 590 | osc_table[osc].pllx, PLLPAXS_MISC_LOCK_ENABLE); |
| 591 | |
Jimmy Zhang | c225e4c | 2014-02-28 17:35:48 -0800 | [diff] [blame] | 592 | /* init pllu */ |
| 593 | init_pll(&clk_rst->pllu_base, &clk_rst->pllu_misc, |
| 594 | osc_table[osc].pllu, PLLUD_MISC_LOCK_ENABLE); |
| 595 | |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 596 | init_utmip_pll(); |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 597 | graphics_pll(); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 598 | } |
| 599 | |
Julius Werner | edf6b57 | 2013-10-25 17:49:26 -0700 | [diff] [blame] | 600 | void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x) |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 601 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 602 | if (l) write32(&clk_rst->clk_enb_l_set, l); |
| 603 | if (h) write32(&clk_rst->clk_enb_h_set, h); |
| 604 | if (u) write32(&clk_rst->clk_enb_u_set, u); |
| 605 | if (v) write32(&clk_rst->clk_enb_v_set, v); |
| 606 | if (w) write32(&clk_rst->clk_enb_w_set, w); |
| 607 | if (x) write32(&clk_rst->clk_enb_x_set, x); |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 608 | |
Hung-Te Lin | 2fc3b62 | 2013-10-21 21:43:03 +0800 | [diff] [blame] | 609 | /* Give clocks time to stabilize. */ |
Gabe Black | d40be11 | 2013-10-09 23:45:07 -0700 | [diff] [blame] | 610 | udelay(IO_STABILIZATION_DELAY); |
| 611 | |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 612 | if (l) write32(&clk_rst->rst_dev_l_clr, l); |
| 613 | if (h) write32(&clk_rst->rst_dev_h_clr, h); |
| 614 | if (u) write32(&clk_rst->rst_dev_u_clr, u); |
| 615 | if (v) write32(&clk_rst->rst_dev_v_clr, v); |
| 616 | if (w) write32(&clk_rst->rst_dev_w_clr, w); |
| 617 | if (x) write32(&clk_rst->rst_dev_x_clr, x); |
Ronald G. Minnich | 3eab7ed | 2013-10-03 17:05:55 -0700 | [diff] [blame] | 618 | } |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 619 | |
| 620 | void clock_reset_l(u32 bit) |
| 621 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 622 | write32(&clk_rst->rst_dev_l_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 623 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 624 | write32(&clk_rst->rst_dev_l_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 625 | } |
| 626 | |
| 627 | void clock_reset_h(u32 bit) |
| 628 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 629 | write32(&clk_rst->rst_dev_h_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 630 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 631 | write32(&clk_rst->rst_dev_h_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 632 | } |
| 633 | |
| 634 | void clock_reset_u(u32 bit) |
| 635 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 636 | write32(&clk_rst->rst_dev_u_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 637 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 638 | write32(&clk_rst->rst_dev_u_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 639 | } |
| 640 | |
| 641 | void clock_reset_v(u32 bit) |
| 642 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 643 | write32(&clk_rst->rst_dev_v_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 644 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 645 | write32(&clk_rst->rst_dev_v_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 646 | } |
| 647 | |
| 648 | void clock_reset_w(u32 bit) |
| 649 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 650 | write32(&clk_rst->rst_dev_w_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 651 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 652 | write32(&clk_rst->rst_dev_w_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 653 | } |
| 654 | |
| 655 | void clock_reset_x(u32 bit) |
| 656 | { |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 657 | write32(&clk_rst->rst_dev_x_set, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 658 | udelay(1); |
Julius Werner | 2f37bd6 | 2015-02-19 14:51:15 -0800 | [diff] [blame] | 659 | write32(&clk_rst->rst_dev_x_clr, bit); |
Gabe Black | bab7896 | 2014-03-26 21:29:45 -0700 | [diff] [blame] | 660 | } |