1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun */ 26ef2ee5d0SMichal Meloun 27ef2ee5d0SMichal Meloun #include <sys/cdefs.h> 28ef2ee5d0SMichal Meloun __FBSDID("$FreeBSD$"); 29ef2ee5d0SMichal Meloun 30ef2ee5d0SMichal Meloun #include <sys/param.h> 31ef2ee5d0SMichal Meloun #include <sys/systm.h> 32ef2ee5d0SMichal Meloun #include <sys/bus.h> 33ef2ee5d0SMichal Meloun #include <sys/lock.h> 34ef2ee5d0SMichal Meloun #include <sys/mutex.h> 35ef2ee5d0SMichal Meloun #include <sys/rman.h> 36ef2ee5d0SMichal Meloun 37ef2ee5d0SMichal Meloun #include <machine/bus.h> 38ef2ee5d0SMichal Meloun 39ef2ee5d0SMichal Meloun #include <dev/extres/clk/clk.h> 40ef2ee5d0SMichal Meloun 418a7a4683SEmmanuel Vadot #include <dt-bindings/clock/tegra124-car.h> 42ef2ee5d0SMichal Meloun #include "tegra124_car.h" 43ef2ee5d0SMichal Meloun 44ef2ee5d0SMichal Meloun /* #define TEGRA_PLL_DEBUG */ 45ef2ee5d0SMichal Meloun #ifdef TEGRA_PLL_DEBUG 46ef2ee5d0SMichal Meloun #define dprintf(...) printf(__VA_ARGS__) 47ef2ee5d0SMichal Meloun #else 48ef2ee5d0SMichal Meloun #define dprintf(...) 49ef2ee5d0SMichal Meloun #endif 50ef2ee5d0SMichal Meloun 51ef2ee5d0SMichal Meloun /* All PLLs. */ 52ef2ee5d0SMichal Meloun enum pll_type { 53ef2ee5d0SMichal Meloun PLL_M, 54ef2ee5d0SMichal Meloun PLL_X, 55ef2ee5d0SMichal Meloun PLL_C, 56ef2ee5d0SMichal Meloun PLL_C2, 57ef2ee5d0SMichal Meloun PLL_C3, 58ef2ee5d0SMichal Meloun PLL_C4, 59ef2ee5d0SMichal Meloun PLL_P, 60ef2ee5d0SMichal Meloun PLL_A, 61ef2ee5d0SMichal Meloun PLL_U, 62ef2ee5d0SMichal Meloun PLL_D, 63ef2ee5d0SMichal Meloun PLL_D2, 64ef2ee5d0SMichal Meloun PLL_DP, 65ef2ee5d0SMichal Meloun PLL_E, 66ef2ee5d0SMichal Meloun PLL_REFE}; 67ef2ee5d0SMichal Meloun 68ef2ee5d0SMichal Meloun /* Common base register bits. */ 69ef2ee5d0SMichal Meloun #define PLL_BASE_BYPASS (1U << 31) 70ef2ee5d0SMichal Meloun #define PLL_BASE_ENABLE (1 << 30) 71ef2ee5d0SMichal Meloun #define PLL_BASE_REFDISABLE (1 << 29) 72ef2ee5d0SMichal Meloun #define PLL_BASE_LOCK (1 << 27) 73ef2ee5d0SMichal Meloun #define PLL_BASE_DIVM_SHIFT 0 74ef2ee5d0SMichal Meloun #define PLL_BASE_DIVN_SHIFT 8 75ef2ee5d0SMichal Meloun 76ef2ee5d0SMichal Meloun #define PLLRE_MISC_LOCK (1 << 24) 77ef2ee5d0SMichal Meloun 78ef2ee5d0SMichal Meloun #define PLL_MISC_LOCK_ENABLE (1 << 18) 79ef2ee5d0SMichal Meloun #define PLLC_MISC_LOCK_ENABLE (1 << 24) 80ef2ee5d0SMichal Meloun #define PLLDU_MISC_LOCK_ENABLE (1 << 22) 81ef2ee5d0SMichal Meloun #define PLLRE_MISC_LOCK_ENABLE (1 << 30) 82ef2ee5d0SMichal Meloun #define PLLSS_MISC_LOCK_ENABLE (1 << 30) 83ef2ee5d0SMichal Meloun 84ef2ee5d0SMichal Meloun #define PLLC_IDDQ_BIT 26 85ef2ee5d0SMichal Meloun #define PLLX_IDDQ_BIT 3 86ef2ee5d0SMichal Meloun #define PLLRE_IDDQ_BIT 16 87ef2ee5d0SMichal Meloun #define PLLSS_IDDQ_BIT 19 88ef2ee5d0SMichal Meloun 89a2785248SMichal Meloun #define PLL_LOCK_TIMEOUT 5000 90ef2ee5d0SMichal Meloun 91ef2ee5d0SMichal Meloun /* Post divider <-> register value mapping. */ 92ef2ee5d0SMichal Meloun struct pdiv_table { 93ef2ee5d0SMichal Meloun uint32_t divider; /* real divider */ 94ef2ee5d0SMichal Meloun uint32_t value; /* register value */ 95ef2ee5d0SMichal Meloun }; 96ef2ee5d0SMichal Meloun 97ef2ee5d0SMichal Meloun /* Bits definition of M, N and P fields. */ 98ef2ee5d0SMichal Meloun struct mnp_bits { 99ef2ee5d0SMichal Meloun uint32_t m_width; 100ef2ee5d0SMichal Meloun uint32_t n_width; 101ef2ee5d0SMichal Meloun uint32_t p_width; 102ef2ee5d0SMichal Meloun uint32_t p_shift; 103ef2ee5d0SMichal Meloun }; 104ef2ee5d0SMichal Meloun 105ef2ee5d0SMichal Meloun struct clk_pll_def { 106ef2ee5d0SMichal Meloun struct clknode_init_def clkdef; 107ef2ee5d0SMichal Meloun enum pll_type type; 108ef2ee5d0SMichal Meloun uint32_t base_reg; 109ef2ee5d0SMichal Meloun uint32_t misc_reg; 110ef2ee5d0SMichal Meloun uint32_t lock_mask; 111ef2ee5d0SMichal Meloun uint32_t lock_enable; 112ef2ee5d0SMichal Meloun uint32_t iddq_reg; 113ef2ee5d0SMichal Meloun uint32_t iddq_mask; 114ef2ee5d0SMichal Meloun uint32_t flags; 115ef2ee5d0SMichal Meloun struct pdiv_table *pdiv_table; 116ef2ee5d0SMichal Meloun struct mnp_bits mnp_bits; 117ef2ee5d0SMichal Meloun }; 118ef2ee5d0SMichal Meloun 119ef2ee5d0SMichal Meloun #define PLL(_id, cname, pname) \ 120ef2ee5d0SMichal Meloun .clkdef.id = _id, \ 121ef2ee5d0SMichal Meloun .clkdef.name = cname, \ 122ef2ee5d0SMichal Meloun .clkdef.parent_names = (const char *[]){pname}, \ 123ef2ee5d0SMichal Meloun .clkdef.parent_cnt = 1, \ 124ef2ee5d0SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS 125ef2ee5d0SMichal Meloun 126ef2ee5d0SMichal Meloun /* Tegra K1 PLLs 127ef2ee5d0SMichal Meloun PLLM: Clock source for EMC 2x clock 128ef2ee5d0SMichal Meloun PLLX: Clock source for the fast CPU cluster and the shadow CPU 129ef2ee5d0SMichal Meloun PLLC: Clock source for general use 130ef2ee5d0SMichal Meloun PLLC2: Clock source for engine scaling 131ef2ee5d0SMichal Meloun PLLC3: Clock source for engine scaling 132ef2ee5d0SMichal Meloun PLLC4: Clock source for ISP/VI units 133ef2ee5d0SMichal Meloun PLLP: Clock source for most peripherals 134ef2ee5d0SMichal Meloun PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz) 135ef2ee5d0SMichal Meloun PLLU: Clock source for USB PHY, provides 12/60/480 MHz 136ef2ee5d0SMichal Meloun PLLD: Clock sources for the DSI and display subsystem 137ef2ee5d0SMichal Meloun PLLD2: Clock sources for the DSI and display subsystem 138ef2ee5d0SMichal Meloun refPLLe: 139ef2ee5d0SMichal Meloun PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum) 140ef2ee5d0SMichal Meloun PLLDP: Clock source for eDP/LVDS (spread spectrum) 141ef2ee5d0SMichal Meloun 142ef2ee5d0SMichal Meloun DFLLCPU: DFLL clock source for the fast CPU cluster 143ef2ee5d0SMichal Meloun GPCPLL: Clock source for the GPU 144ef2ee5d0SMichal Meloun */ 145ef2ee5d0SMichal Meloun 146ef2ee5d0SMichal Meloun static struct pdiv_table pllm_map[] = { 147ef2ee5d0SMichal Meloun {1, 0}, 148ef2ee5d0SMichal Meloun {2, 1}, 149ef2ee5d0SMichal Meloun {0, 0} 150ef2ee5d0SMichal Meloun }; 151ef2ee5d0SMichal Meloun 152ef2ee5d0SMichal Meloun static struct pdiv_table pllxc_map[] = { 153ef2ee5d0SMichal Meloun { 1, 0}, 154ef2ee5d0SMichal Meloun { 2, 1}, 155ef2ee5d0SMichal Meloun { 3, 2}, 156ef2ee5d0SMichal Meloun { 4, 3}, 157ef2ee5d0SMichal Meloun { 5, 4}, 158ef2ee5d0SMichal Meloun { 6, 5}, 159ef2ee5d0SMichal Meloun { 8, 6}, 160ef2ee5d0SMichal Meloun {10, 7}, 161ef2ee5d0SMichal Meloun {12, 8}, 162ef2ee5d0SMichal Meloun {16, 9}, 163ef2ee5d0SMichal Meloun {12, 10}, 164ef2ee5d0SMichal Meloun {16, 11}, 165ef2ee5d0SMichal Meloun {20, 12}, 166ef2ee5d0SMichal Meloun {24, 13}, 167ef2ee5d0SMichal Meloun {32, 14}, 168ef2ee5d0SMichal Meloun { 0, 0} 169ef2ee5d0SMichal Meloun }; 170ef2ee5d0SMichal Meloun 171ef2ee5d0SMichal Meloun static struct pdiv_table pllc_map[] = { 172ef2ee5d0SMichal Meloun { 1, 0}, 173ef2ee5d0SMichal Meloun { 2, 1}, 174ef2ee5d0SMichal Meloun { 3, 2}, 175ef2ee5d0SMichal Meloun { 4, 3}, 176ef2ee5d0SMichal Meloun { 6, 4}, 177ef2ee5d0SMichal Meloun { 8, 5}, 178ef2ee5d0SMichal Meloun {12, 6}, 179ef2ee5d0SMichal Meloun {16, 7}, 180ef2ee5d0SMichal Meloun { 0, 0} 181ef2ee5d0SMichal Meloun }; 182ef2ee5d0SMichal Meloun 183ef2ee5d0SMichal Meloun static struct pdiv_table pll12g_ssd_esd_map[] = { 184ef2ee5d0SMichal Meloun { 1, 0}, 185ef2ee5d0SMichal Meloun { 2, 1}, 186ef2ee5d0SMichal Meloun { 3, 2}, 187ef2ee5d0SMichal Meloun { 4, 3}, 188ef2ee5d0SMichal Meloun { 5, 4}, 189ef2ee5d0SMichal Meloun { 6, 5}, 190ef2ee5d0SMichal Meloun { 8, 6}, 191ef2ee5d0SMichal Meloun {10, 7}, 192ef2ee5d0SMichal Meloun {12, 8}, 193ef2ee5d0SMichal Meloun {16, 9}, 194ef2ee5d0SMichal Meloun {12, 10}, 195ef2ee5d0SMichal Meloun {16, 11}, 196ef2ee5d0SMichal Meloun {20, 12}, 197ef2ee5d0SMichal Meloun {24, 13}, 198ef2ee5d0SMichal Meloun {32, 14}, 199ef2ee5d0SMichal Meloun { 0, 0} 200ef2ee5d0SMichal Meloun }; 201ef2ee5d0SMichal Meloun 202ef2ee5d0SMichal Meloun static struct pdiv_table pllu_map[] = { 203ef2ee5d0SMichal Meloun {1, 1}, 204ef2ee5d0SMichal Meloun {2, 0}, 205ef2ee5d0SMichal Meloun {0, 0} 206ef2ee5d0SMichal Meloun }; 207ef2ee5d0SMichal Meloun 2087961a970SMichal Meloun static struct pdiv_table pllrefe_map[] = { 2097961a970SMichal Meloun {1, 0}, 2107961a970SMichal Meloun {2, 1}, 2117961a970SMichal Meloun {3, 2}, 2127961a970SMichal Meloun {4, 3}, 2137961a970SMichal Meloun {5, 4}, 2147961a970SMichal Meloun {6, 5}, 2157961a970SMichal Meloun {0, 0}, 2167961a970SMichal Meloun }; 2177961a970SMichal Meloun 218ef2ee5d0SMichal Meloun static struct clk_pll_def pll_clks[] = { 219ef2ee5d0SMichal Meloun /* PLLM: 880 MHz Clock source for EMC 2x clock */ 220ef2ee5d0SMichal Meloun { 221ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_M, "pllM_out0", "osc_div_clk"), 222ef2ee5d0SMichal Meloun .type = PLL_M, 223ef2ee5d0SMichal Meloun .base_reg = PLLM_BASE, 224ef2ee5d0SMichal Meloun .misc_reg = PLLM_MISC, 225ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 226ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 227ef2ee5d0SMichal Meloun .pdiv_table = pllm_map, 228ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 1, 20}, 229ef2ee5d0SMichal Meloun }, 230ef2ee5d0SMichal Meloun /* PLLX: 1GHz Clock source for the fast CPU cluster and the shadow CPU */ 231ef2ee5d0SMichal Meloun { 232ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_X, "pllX_out", "osc_div_clk"), 233ef2ee5d0SMichal Meloun .type = PLL_X, 234ef2ee5d0SMichal Meloun .base_reg = PLLX_BASE, 235ef2ee5d0SMichal Meloun .misc_reg = PLLX_MISC, 236ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 237ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 238ef2ee5d0SMichal Meloun .iddq_reg = PLLX_MISC3, 239ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLX_IDDQ_BIT, 240ef2ee5d0SMichal Meloun .pdiv_table = pllxc_map, 241ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 20}, 242ef2ee5d0SMichal Meloun }, 243ef2ee5d0SMichal Meloun /* PLLC: 600 MHz Clock source for general use */ 244ef2ee5d0SMichal Meloun { 245ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_C, "pllC_out0", "osc_div_clk"), 246ef2ee5d0SMichal Meloun .type = PLL_C, 247ef2ee5d0SMichal Meloun .base_reg = PLLC_BASE, 248ef2ee5d0SMichal Meloun .misc_reg = PLLC_MISC, 249ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 250ef2ee5d0SMichal Meloun .lock_enable = PLLC_MISC_LOCK_ENABLE, 251ef2ee5d0SMichal Meloun .iddq_reg = PLLC_MISC, 252ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLC_IDDQ_BIT, 253ef2ee5d0SMichal Meloun .pdiv_table = pllc_map, 254ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 20}, 255ef2ee5d0SMichal Meloun }, 256ef2ee5d0SMichal Meloun /* PLLC2: 600 MHz Clock source for engine scaling */ 257ef2ee5d0SMichal Meloun { 258ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_C2, "pllC2_out0", "osc_div_clk"), 259ef2ee5d0SMichal Meloun .type = PLL_C2, 260ef2ee5d0SMichal Meloun .base_reg = PLLC2_BASE, 261ef2ee5d0SMichal Meloun .misc_reg = PLLC2_MISC, 262ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 263ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 264ef2ee5d0SMichal Meloun .pdiv_table = pllc_map, 265ef2ee5d0SMichal Meloun .mnp_bits = {2, 8, 3, 20}, 266ef2ee5d0SMichal Meloun }, 267ef2ee5d0SMichal Meloun /* PLLC3: 600 MHz Clock source for engine scaling */ 268ef2ee5d0SMichal Meloun { 269ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_C3, "pllC3_out0", "osc_div_clk"), 270ef2ee5d0SMichal Meloun .type = PLL_C3, 271ef2ee5d0SMichal Meloun .base_reg = PLLC3_BASE, 272ef2ee5d0SMichal Meloun .misc_reg = PLLC3_MISC, 273ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 274ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 275ef2ee5d0SMichal Meloun .pdiv_table = pllc_map, 276ef2ee5d0SMichal Meloun .mnp_bits = {2, 8, 3, 20}, 277ef2ee5d0SMichal Meloun }, 278ef2ee5d0SMichal Meloun /* PLLC4: 600 MHz Clock source for ISP/VI units */ 279ef2ee5d0SMichal Meloun { 280ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_C4, "pllC4_out0", "pllC4_src"), 281ef2ee5d0SMichal Meloun .type = PLL_C4, 282ef2ee5d0SMichal Meloun .base_reg = PLLC4_BASE, 283ef2ee5d0SMichal Meloun .misc_reg = PLLC4_MISC, 284ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 285ef2ee5d0SMichal Meloun .lock_enable = PLLSS_MISC_LOCK_ENABLE, 286ef2ee5d0SMichal Meloun .iddq_reg = PLLC4_BASE, 287ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLSS_IDDQ_BIT, 288ef2ee5d0SMichal Meloun .pdiv_table = pll12g_ssd_esd_map, 289ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 20}, 290ef2ee5d0SMichal Meloun }, 291ef2ee5d0SMichal Meloun /* PLLP: 408 MHz Clock source for most peripherals */ 292ef2ee5d0SMichal Meloun { 293ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_P, "pllP_out0", "osc_div_clk"), 294ef2ee5d0SMichal Meloun .type = PLL_P, 295ef2ee5d0SMichal Meloun .base_reg = PLLP_BASE, 296ef2ee5d0SMichal Meloun .misc_reg = PLLP_MISC, 297ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 298ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 299ef2ee5d0SMichal Meloun .mnp_bits = {5, 10, 3, 20}, 300ef2ee5d0SMichal Meloun }, 301ef2ee5d0SMichal Meloun /* PLLA: Audio clock sources: (11.2896 MHz, 12.288 MHz, 24.576 MHz) */ 302ef2ee5d0SMichal Meloun { 303ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_A, "pllA_out", "pllP_out1"), 304ef2ee5d0SMichal Meloun .type = PLL_A, 305ef2ee5d0SMichal Meloun .base_reg = PLLA_BASE, 306ef2ee5d0SMichal Meloun .misc_reg = PLLA_MISC, 307ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 308ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 309ef2ee5d0SMichal Meloun .mnp_bits = {5, 10, 3, 20}, 310ef2ee5d0SMichal Meloun }, 311ef2ee5d0SMichal Meloun /* PLLU: 480 MHz Clock source for USB PHY, provides 12/60/480 MHz */ 312ef2ee5d0SMichal Meloun { 313ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_U, "pllU_out", "osc_div_clk"), 314ef2ee5d0SMichal Meloun .type = PLL_U, 315ef2ee5d0SMichal Meloun .base_reg = PLLU_BASE, 316ef2ee5d0SMichal Meloun .misc_reg = PLLU_MISC, 317ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 318ef2ee5d0SMichal Meloun .lock_enable = PLLDU_MISC_LOCK_ENABLE, 319ef2ee5d0SMichal Meloun .pdiv_table = pllu_map, 320ef2ee5d0SMichal Meloun .mnp_bits = {5, 10, 1, 20}, 321ef2ee5d0SMichal Meloun }, 322ef2ee5d0SMichal Meloun /* PLLD: 600 MHz Clock sources for the DSI and display subsystem */ 323ef2ee5d0SMichal Meloun { 324ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_D, "pllD_out", "osc_div_clk"), 325ef2ee5d0SMichal Meloun .type = PLL_D, 326ef2ee5d0SMichal Meloun .base_reg = PLLD_BASE, 327ef2ee5d0SMichal Meloun .misc_reg = PLLD_MISC, 328ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 329ef2ee5d0SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 330ef2ee5d0SMichal Meloun .mnp_bits = {5, 11, 3, 20}, 331ef2ee5d0SMichal Meloun }, 332ef2ee5d0SMichal Meloun /* PLLD2: 600 MHz Clock sources for the DSI and display subsystem */ 333ef2ee5d0SMichal Meloun { 334ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_D2, "pllD2_out", "pllD2_src"), 335ef2ee5d0SMichal Meloun .type = PLL_D2, 336ef2ee5d0SMichal Meloun .base_reg = PLLD2_BASE, 337ef2ee5d0SMichal Meloun .misc_reg = PLLD2_MISC, 338ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 339ef2ee5d0SMichal Meloun .lock_enable = PLLSS_MISC_LOCK_ENABLE, 340ef2ee5d0SMichal Meloun .iddq_reg = PLLD2_BASE, 341ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLSS_IDDQ_BIT, 342ef2ee5d0SMichal Meloun .pdiv_table = pll12g_ssd_esd_map, 343ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 20}, 344ef2ee5d0SMichal Meloun }, 345ef2ee5d0SMichal Meloun /* refPLLe: */ 346ef2ee5d0SMichal Meloun { 347ef2ee5d0SMichal Meloun PLL(0, "pllREFE_out", "osc_div_clk"), 348ef2ee5d0SMichal Meloun .type = PLL_REFE, 349ef2ee5d0SMichal Meloun .base_reg = PLLRE_BASE, 350ef2ee5d0SMichal Meloun .misc_reg = PLLRE_MISC, 351ef2ee5d0SMichal Meloun .lock_mask = PLLRE_MISC_LOCK, 352ef2ee5d0SMichal Meloun .lock_enable = PLLRE_MISC_LOCK_ENABLE, 353ef2ee5d0SMichal Meloun .iddq_reg = PLLRE_MISC, 354ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLRE_IDDQ_BIT, 3557961a970SMichal Meloun .pdiv_table = pllrefe_map, 356ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 16}, 357ef2ee5d0SMichal Meloun }, 358ef2ee5d0SMichal Meloun /* PLLE: generate the 100 MHz reference clock for USB 3.0 (spread spectrum) */ 359ef2ee5d0SMichal Meloun { 360ef2ee5d0SMichal Meloun PLL(TEGRA124_CLK_PLL_E, "pllE_out0", "pllE_src"), 361ef2ee5d0SMichal Meloun .type = PLL_E, 362ef2ee5d0SMichal Meloun .base_reg = PLLE_BASE, 363ef2ee5d0SMichal Meloun .misc_reg = PLLE_MISC, 364ef2ee5d0SMichal Meloun .lock_mask = PLLE_MISC_LOCK, 365ef2ee5d0SMichal Meloun .lock_enable = PLLE_MISC_LOCK_ENABLE, 366ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 24}, 367ef2ee5d0SMichal Meloun }, 368ef2ee5d0SMichal Meloun /* PLLDP: 600 MHz Clock source for eDP/LVDS (spread spectrum) */ 369ef2ee5d0SMichal Meloun { 370ef2ee5d0SMichal Meloun PLL(0, "pllDP_out0", "pllDP_src"), 371ef2ee5d0SMichal Meloun .type = PLL_DP, 372ef2ee5d0SMichal Meloun .base_reg = PLLDP_BASE, 373ef2ee5d0SMichal Meloun .misc_reg = PLLDP_MISC, 374ef2ee5d0SMichal Meloun .lock_mask = PLL_BASE_LOCK, 375ef2ee5d0SMichal Meloun .lock_enable = PLLSS_MISC_LOCK_ENABLE, 376ef2ee5d0SMichal Meloun .iddq_reg = PLLDP_BASE, 377ef2ee5d0SMichal Meloun .iddq_mask = 1 << PLLSS_IDDQ_BIT, 378ef2ee5d0SMichal Meloun .pdiv_table = pll12g_ssd_esd_map, 379ef2ee5d0SMichal Meloun .mnp_bits = {8, 8, 4, 20}, 380ef2ee5d0SMichal Meloun }, 381ef2ee5d0SMichal Meloun }; 382ef2ee5d0SMichal Meloun 383ef2ee5d0SMichal Meloun static int tegra124_pll_init(struct clknode *clk, device_t dev); 384ef2ee5d0SMichal Meloun static int tegra124_pll_set_gate(struct clknode *clk, bool enable); 385be01656fSMichal Meloun static int tegra124_pll_get_gate(struct clknode *clk, bool *enabled); 386ef2ee5d0SMichal Meloun static int tegra124_pll_recalc(struct clknode *clk, uint64_t *freq); 387ef2ee5d0SMichal Meloun static int tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin, 388ef2ee5d0SMichal Meloun uint64_t *fout, int flags, int *stop); 389ef2ee5d0SMichal Meloun struct pll_sc { 390ef2ee5d0SMichal Meloun device_t clkdev; 391ef2ee5d0SMichal Meloun enum pll_type type; 392ef2ee5d0SMichal Meloun uint32_t base_reg; 393ef2ee5d0SMichal Meloun uint32_t misc_reg; 394ef2ee5d0SMichal Meloun uint32_t lock_mask; 395ef2ee5d0SMichal Meloun uint32_t lock_enable; 396ef2ee5d0SMichal Meloun uint32_t iddq_reg; 397ef2ee5d0SMichal Meloun uint32_t iddq_mask; 398ef2ee5d0SMichal Meloun uint32_t flags; 399ef2ee5d0SMichal Meloun struct pdiv_table *pdiv_table; 400ef2ee5d0SMichal Meloun struct mnp_bits mnp_bits; 401ef2ee5d0SMichal Meloun }; 402ef2ee5d0SMichal Meloun 403ef2ee5d0SMichal Meloun static clknode_method_t tegra124_pll_methods[] = { 404ef2ee5d0SMichal Meloun /* Device interface */ 405ef2ee5d0SMichal Meloun CLKNODEMETHOD(clknode_init, tegra124_pll_init), 406ef2ee5d0SMichal Meloun CLKNODEMETHOD(clknode_set_gate, tegra124_pll_set_gate), 407be01656fSMichal Meloun CLKNODEMETHOD(clknode_get_gate, tegra124_pll_get_gate), 408ef2ee5d0SMichal Meloun CLKNODEMETHOD(clknode_recalc_freq, tegra124_pll_recalc), 409ef2ee5d0SMichal Meloun CLKNODEMETHOD(clknode_set_freq, tegra124_pll_set_freq), 410ef2ee5d0SMichal Meloun CLKNODEMETHOD_END 411ef2ee5d0SMichal Meloun }; 412ef2ee5d0SMichal Meloun DEFINE_CLASS_1(tegra124_pll, tegra124_pll_class, tegra124_pll_methods, 413ef2ee5d0SMichal Meloun sizeof(struct pll_sc), clknode_class); 414ef2ee5d0SMichal Meloun 415ef2ee5d0SMichal Meloun static int 416ef2ee5d0SMichal Meloun pll_enable(struct pll_sc *sc) 417ef2ee5d0SMichal Meloun { 418ef2ee5d0SMichal Meloun uint32_t reg; 419ef2ee5d0SMichal Meloun 420ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 421ef2ee5d0SMichal Meloun if (sc->type != PLL_E) 422ef2ee5d0SMichal Meloun reg &= ~PLL_BASE_BYPASS; 423ef2ee5d0SMichal Meloun reg |= PLL_BASE_ENABLE; 424ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 425ef2ee5d0SMichal Meloun return (0); 426ef2ee5d0SMichal Meloun } 427ef2ee5d0SMichal Meloun 428ef2ee5d0SMichal Meloun static int 429ef2ee5d0SMichal Meloun pll_disable(struct pll_sc *sc) 430ef2ee5d0SMichal Meloun { 431ef2ee5d0SMichal Meloun uint32_t reg; 432ef2ee5d0SMichal Meloun 433ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 434ef2ee5d0SMichal Meloun if (sc->type != PLL_E) 435ef2ee5d0SMichal Meloun reg |= PLL_BASE_BYPASS; 436ef2ee5d0SMichal Meloun reg &= ~PLL_BASE_ENABLE; 437ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 438ef2ee5d0SMichal Meloun return (0); 439ef2ee5d0SMichal Meloun } 440ef2ee5d0SMichal Meloun 441ef2ee5d0SMichal Meloun static uint32_t 442ef2ee5d0SMichal Meloun pdiv_to_reg(struct pll_sc *sc, uint32_t p_div) 443ef2ee5d0SMichal Meloun { 444ef2ee5d0SMichal Meloun struct pdiv_table *tbl; 445ef2ee5d0SMichal Meloun 446ef2ee5d0SMichal Meloun tbl = sc->pdiv_table; 447ef2ee5d0SMichal Meloun if (tbl == NULL) 4487961a970SMichal Meloun return (ffs(p_div) - 1); 449ef2ee5d0SMichal Meloun 450ef2ee5d0SMichal Meloun while (tbl->divider != 0) { 451ef2ee5d0SMichal Meloun if (p_div <= tbl->divider) 452ef2ee5d0SMichal Meloun return (tbl->value); 453ef2ee5d0SMichal Meloun tbl++; 454ef2ee5d0SMichal Meloun } 4557961a970SMichal Meloun return (0xFFFFFFFF); 456ef2ee5d0SMichal Meloun } 457ef2ee5d0SMichal Meloun 458ef2ee5d0SMichal Meloun static uint32_t 459ef2ee5d0SMichal Meloun reg_to_pdiv(struct pll_sc *sc, uint32_t reg) 460ef2ee5d0SMichal Meloun { 461ef2ee5d0SMichal Meloun struct pdiv_table *tbl; 462ef2ee5d0SMichal Meloun 463ef2ee5d0SMichal Meloun tbl = sc->pdiv_table; 4647961a970SMichal Meloun if (tbl == NULL) 4657961a970SMichal Meloun return (1 << reg); 4667961a970SMichal Meloun 467ef2ee5d0SMichal Meloun while (tbl->divider) { 468ef2ee5d0SMichal Meloun if (reg == tbl->value) 469ef2ee5d0SMichal Meloun return (tbl->divider); 470ef2ee5d0SMichal Meloun tbl++; 471ef2ee5d0SMichal Meloun } 472ef2ee5d0SMichal Meloun return (0); 473ef2ee5d0SMichal Meloun } 474ef2ee5d0SMichal Meloun 475ef2ee5d0SMichal Meloun static uint32_t 476ef2ee5d0SMichal Meloun get_masked(uint32_t val, uint32_t shift, uint32_t width) 477ef2ee5d0SMichal Meloun { 478ef2ee5d0SMichal Meloun 479ef2ee5d0SMichal Meloun return ((val >> shift) & ((1 << width) - 1)); 480ef2ee5d0SMichal Meloun } 481ef2ee5d0SMichal Meloun 482ef2ee5d0SMichal Meloun static uint32_t 483ef2ee5d0SMichal Meloun set_masked(uint32_t val, uint32_t v, uint32_t shift, uint32_t width) 484ef2ee5d0SMichal Meloun { 485ef2ee5d0SMichal Meloun 486ef2ee5d0SMichal Meloun val &= ~(((1 << width) - 1) << shift); 487ef2ee5d0SMichal Meloun val |= (v & ((1 << width) - 1)) << shift; 488ef2ee5d0SMichal Meloun return (val); 489ef2ee5d0SMichal Meloun } 490ef2ee5d0SMichal Meloun 491ef2ee5d0SMichal Meloun static void 492ef2ee5d0SMichal Meloun get_divisors(struct pll_sc *sc, uint32_t *m, uint32_t *n, uint32_t *p) 493ef2ee5d0SMichal Meloun { 494ef2ee5d0SMichal Meloun uint32_t val; 495ef2ee5d0SMichal Meloun struct mnp_bits *mnp_bits; 496ef2ee5d0SMichal Meloun 497ef2ee5d0SMichal Meloun mnp_bits = &sc->mnp_bits; 498ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, &val); 499ef2ee5d0SMichal Meloun *m = get_masked(val, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width); 500ef2ee5d0SMichal Meloun *n = get_masked(val, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width); 501ef2ee5d0SMichal Meloun *p = get_masked(val, mnp_bits->p_shift, mnp_bits->p_width); 502ef2ee5d0SMichal Meloun } 503ef2ee5d0SMichal Meloun 504ef2ee5d0SMichal Meloun static uint32_t 505ef2ee5d0SMichal Meloun set_divisors(struct pll_sc *sc, uint32_t val, uint32_t m, uint32_t n, 506ef2ee5d0SMichal Meloun uint32_t p) 507ef2ee5d0SMichal Meloun { 508ef2ee5d0SMichal Meloun struct mnp_bits *mnp_bits; 509ef2ee5d0SMichal Meloun 510ef2ee5d0SMichal Meloun mnp_bits = &sc->mnp_bits; 511ef2ee5d0SMichal Meloun val = set_masked(val, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width); 512ef2ee5d0SMichal Meloun val = set_masked(val, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width); 513ef2ee5d0SMichal Meloun val = set_masked(val, p, mnp_bits->p_shift, mnp_bits->p_width); 514ef2ee5d0SMichal Meloun return (val); 515ef2ee5d0SMichal Meloun } 516ef2ee5d0SMichal Meloun 517ef2ee5d0SMichal Meloun static bool 518ef2ee5d0SMichal Meloun is_locked(struct pll_sc *sc) 519ef2ee5d0SMichal Meloun { 520ef2ee5d0SMichal Meloun uint32_t reg; 521ef2ee5d0SMichal Meloun 522ef2ee5d0SMichal Meloun switch (sc->type) { 523ef2ee5d0SMichal Meloun case PLL_REFE: 524ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 525ef2ee5d0SMichal Meloun reg &= PLLRE_MISC_LOCK; 526ef2ee5d0SMichal Meloun break; 527ef2ee5d0SMichal Meloun 528ef2ee5d0SMichal Meloun case PLL_E: 529ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 530ef2ee5d0SMichal Meloun reg &= PLLE_MISC_LOCK; 531ef2ee5d0SMichal Meloun break; 532ef2ee5d0SMichal Meloun 533ef2ee5d0SMichal Meloun default: 534ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 535ef2ee5d0SMichal Meloun reg &= PLL_BASE_LOCK; 536ef2ee5d0SMichal Meloun break; 537ef2ee5d0SMichal Meloun } 538ef2ee5d0SMichal Meloun return (reg != 0); 539ef2ee5d0SMichal Meloun } 540ef2ee5d0SMichal Meloun 541ef2ee5d0SMichal Meloun static int 542ef2ee5d0SMichal Meloun wait_for_lock(struct pll_sc *sc) 543ef2ee5d0SMichal Meloun { 544ef2ee5d0SMichal Meloun int i; 545ef2ee5d0SMichal Meloun 546ef2ee5d0SMichal Meloun for (i = PLL_LOCK_TIMEOUT / 10; i > 0; i--) { 547ef2ee5d0SMichal Meloun if (is_locked(sc)) 548ef2ee5d0SMichal Meloun break; 549ef2ee5d0SMichal Meloun DELAY(10); 550ef2ee5d0SMichal Meloun } 551ef2ee5d0SMichal Meloun if (i <= 0) { 552ef2ee5d0SMichal Meloun printf("PLL lock timeout\n"); 553ef2ee5d0SMichal Meloun return (ETIMEDOUT); 554ef2ee5d0SMichal Meloun } 555ef2ee5d0SMichal Meloun return (0); 556ef2ee5d0SMichal Meloun } 557ef2ee5d0SMichal Meloun 558ef2ee5d0SMichal Meloun static int 559ef2ee5d0SMichal Meloun plle_enable(struct pll_sc *sc) 560ef2ee5d0SMichal Meloun { 561ef2ee5d0SMichal Meloun uint32_t reg; 562ef2ee5d0SMichal Meloun int rv; 563ef2ee5d0SMichal Meloun uint32_t pll_m = 1; 564ef2ee5d0SMichal Meloun uint32_t pll_n = 200; 565ef2ee5d0SMichal Meloun uint32_t pll_p = 13; 566ef2ee5d0SMichal Meloun uint32_t pll_cml = 13; 567ef2ee5d0SMichal Meloun 568ef2ee5d0SMichal Meloun /* Disable lock override. */ 569ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 570ef2ee5d0SMichal Meloun reg &= ~PLLE_BASE_LOCK_OVERRIDE; 571ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 572ef2ee5d0SMichal Meloun 573ef2ee5d0SMichal Meloun RD4(sc, PLLE_AUX, ®); 574ef2ee5d0SMichal Meloun reg |= PLLE_AUX_ENABLE_SWCTL; 575ef2ee5d0SMichal Meloun reg &= ~PLLE_AUX_SEQ_ENABLE; 576ef2ee5d0SMichal Meloun WR4(sc, PLLE_AUX, reg); 577ef2ee5d0SMichal Meloun DELAY(10); 578ef2ee5d0SMichal Meloun 579ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 580ef2ee5d0SMichal Meloun reg |= PLLE_MISC_LOCK_ENABLE; 581ef2ee5d0SMichal Meloun reg |= PLLE_MISC_IDDQ_SWCTL; 582ef2ee5d0SMichal Meloun reg &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE; 583ef2ee5d0SMichal Meloun reg |= PLLE_MISC_PTS; 584ef2ee5d0SMichal Meloun reg |= PLLE_MISC_VREG_BG_CTRL_MASK; 585ef2ee5d0SMichal Meloun reg |= PLLE_MISC_VREG_CTRL_MASK; 586ef2ee5d0SMichal Meloun WR4(sc, sc->misc_reg, reg); 587ef2ee5d0SMichal Meloun DELAY(10); 588ef2ee5d0SMichal Meloun 589ef2ee5d0SMichal Meloun RD4(sc, PLLE_SS_CNTL, ®); 590ef2ee5d0SMichal Meloun reg |= PLLE_SS_CNTL_DISABLE; 591ef2ee5d0SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 592ef2ee5d0SMichal Meloun 593ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 594ef2ee5d0SMichal Meloun reg = set_divisors(sc, reg, pll_m, pll_n, pll_p); 595ef2ee5d0SMichal Meloun reg &= ~(PLLE_BASE_DIVCML_MASK << PLLE_BASE_DIVCML_SHIFT); 596ef2ee5d0SMichal Meloun reg |= pll_cml << PLLE_BASE_DIVCML_SHIFT; 597ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 598ef2ee5d0SMichal Meloun DELAY(10); 599ef2ee5d0SMichal Meloun 600ef2ee5d0SMichal Meloun pll_enable(sc); 601ef2ee5d0SMichal Meloun rv = wait_for_lock(sc); 602ef2ee5d0SMichal Meloun if (rv != 0) 603ef2ee5d0SMichal Meloun return (rv); 604ef2ee5d0SMichal Meloun 605ef2ee5d0SMichal Meloun RD4(sc, PLLE_SS_CNTL, ®); 606ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCCENTER; 607ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCINVERT; 608ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_COEFFICIENTS_MASK; 609ef2ee5d0SMichal Meloun reg |= PLLE_SS_CNTL_COEFFICIENTS_VAL; 610ef2ee5d0SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 611ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCBYP; 612ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_BYPASS_SS; 613ef2ee5d0SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 614ef2ee5d0SMichal Meloun DELAY(10); 615ef2ee5d0SMichal Meloun 616ef2ee5d0SMichal Meloun reg &= ~PLLE_SS_CNTL_INTERP_RESET; 617ef2ee5d0SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 618ef2ee5d0SMichal Meloun DELAY(10); 619ef2ee5d0SMichal Meloun 620ef2ee5d0SMichal Meloun /* HW control of brick pll. */ 621ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 622ef2ee5d0SMichal Meloun reg &= ~PLLE_MISC_IDDQ_SWCTL; 623ef2ee5d0SMichal Meloun WR4(sc, sc->misc_reg, reg); 624ef2ee5d0SMichal Meloun 625ef2ee5d0SMichal Meloun RD4(sc, PLLE_AUX, ®); 626ef2ee5d0SMichal Meloun reg |= PLLE_AUX_USE_LOCKDET; 627ef2ee5d0SMichal Meloun reg |= PLLE_AUX_SEQ_START_STATE; 628ef2ee5d0SMichal Meloun reg &= ~PLLE_AUX_ENABLE_SWCTL; 629ef2ee5d0SMichal Meloun reg &= ~PLLE_AUX_SS_SWCTL; 630ef2ee5d0SMichal Meloun WR4(sc, PLLE_AUX, reg); 631ef2ee5d0SMichal Meloun reg |= PLLE_AUX_SEQ_START_STATE; 632ef2ee5d0SMichal Meloun DELAY(10); 633ef2ee5d0SMichal Meloun reg |= PLLE_AUX_SEQ_ENABLE; 634ef2ee5d0SMichal Meloun WR4(sc, PLLE_AUX, reg); 635ef2ee5d0SMichal Meloun 636ef2ee5d0SMichal Meloun RD4(sc, XUSBIO_PLL_CFG0, ®); 637ef2ee5d0SMichal Meloun reg |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET; 638ef2ee5d0SMichal Meloun reg |= XUSBIO_PLL_CFG0_SEQ_START_STATE; 639ef2ee5d0SMichal Meloun reg &= ~XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL; 640ef2ee5d0SMichal Meloun reg &= ~XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL; 641ef2ee5d0SMichal Meloun WR4(sc, XUSBIO_PLL_CFG0, reg); 642ef2ee5d0SMichal Meloun DELAY(10); 643ef2ee5d0SMichal Meloun 644ef2ee5d0SMichal Meloun reg |= XUSBIO_PLL_CFG0_SEQ_ENABLE; 645ef2ee5d0SMichal Meloun WR4(sc, XUSBIO_PLL_CFG0, reg); 646ef2ee5d0SMichal Meloun 647ef2ee5d0SMichal Meloun /* Enable HW control and unreset SATA PLL. */ 648ef2ee5d0SMichal Meloun RD4(sc, SATA_PLL_CFG0, ®); 649ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; 650ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_PADPLL_RESET_OVERRIDE_VALUE; 651ef2ee5d0SMichal Meloun reg |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET; 652ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_IN_SWCTL; 653ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_RESET_INPUT_VALUE; 654ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_LANE_PD_INPUT_VALUE; 655ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_PADPLL_PD_INPUT_VALUE; 656ef2ee5d0SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_ENABLE; 657ef2ee5d0SMichal Meloun reg |= SATA_PLL_CFG0_SEQ_START_STATE; 658ef2ee5d0SMichal Meloun WR4(sc, SATA_PLL_CFG0, reg); 659ef2ee5d0SMichal Meloun DELAY(10); 660ef2ee5d0SMichal Meloun reg |= SATA_PLL_CFG0_SEQ_ENABLE; 661ef2ee5d0SMichal Meloun WR4(sc, SATA_PLL_CFG0, reg); 662ef2ee5d0SMichal Meloun 663ef2ee5d0SMichal Meloun /* Enable HW control of PCIe PLL. */ 664ef2ee5d0SMichal Meloun RD4(sc, PCIE_PLL_CFG0, ®); 665ef2ee5d0SMichal Meloun reg |= PCIE_PLL_CFG0_SEQ_ENABLE; 666ef2ee5d0SMichal Meloun WR4(sc, PCIE_PLL_CFG0, reg); 667ef2ee5d0SMichal Meloun 668ef2ee5d0SMichal Meloun return (0); 669ef2ee5d0SMichal Meloun } 670ef2ee5d0SMichal Meloun 671ef2ee5d0SMichal Meloun static int 672ef2ee5d0SMichal Meloun tegra124_pll_set_gate(struct clknode *clknode, bool enable) 673ef2ee5d0SMichal Meloun { 674ef2ee5d0SMichal Meloun int rv; 675ef2ee5d0SMichal Meloun struct pll_sc *sc; 676ef2ee5d0SMichal Meloun 677ef2ee5d0SMichal Meloun sc = clknode_get_softc(clknode); 678ef2ee5d0SMichal Meloun if (enable == 0) { 679ef2ee5d0SMichal Meloun rv = pll_disable(sc); 680ef2ee5d0SMichal Meloun return(rv); 681ef2ee5d0SMichal Meloun } 682ef2ee5d0SMichal Meloun 683ef2ee5d0SMichal Meloun if (sc->type == PLL_E) 684ef2ee5d0SMichal Meloun rv = plle_enable(sc); 685ef2ee5d0SMichal Meloun else 686ef2ee5d0SMichal Meloun rv = pll_enable(sc); 687ef2ee5d0SMichal Meloun return (rv); 688ef2ee5d0SMichal Meloun } 689ef2ee5d0SMichal Meloun 690ef2ee5d0SMichal Meloun static int 691be01656fSMichal Meloun tegra124_pll_get_gate(struct clknode *clknode, bool *enabled) 692be01656fSMichal Meloun { 693be01656fSMichal Meloun uint32_t reg; 694be01656fSMichal Meloun struct pll_sc *sc; 695be01656fSMichal Meloun 696be01656fSMichal Meloun sc = clknode_get_softc(clknode); 697be01656fSMichal Meloun RD4(sc, sc->base_reg, ®); 698be01656fSMichal Meloun *enabled = reg & PLL_BASE_ENABLE ? true: false; 699be01656fSMichal Meloun WR4(sc, sc->base_reg, reg); 700be01656fSMichal Meloun return (0); 701be01656fSMichal Meloun } 702be01656fSMichal Meloun 703be01656fSMichal Meloun static int 704ef2ee5d0SMichal Meloun pll_set_std(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags, 705ef2ee5d0SMichal Meloun uint32_t m, uint32_t n, uint32_t p) 706ef2ee5d0SMichal Meloun { 707ef2ee5d0SMichal Meloun uint32_t reg; 708ef2ee5d0SMichal Meloun struct mnp_bits *mnp_bits; 709ef2ee5d0SMichal Meloun int rv; 710ef2ee5d0SMichal Meloun 711ef2ee5d0SMichal Meloun mnp_bits = &sc->mnp_bits; 712ef2ee5d0SMichal Meloun if (m >= (1 << mnp_bits->m_width)) 713ef2ee5d0SMichal Meloun return (ERANGE); 714ef2ee5d0SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 715ef2ee5d0SMichal Meloun return (ERANGE); 716ef2ee5d0SMichal Meloun if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width)) 717ef2ee5d0SMichal Meloun return (ERANGE); 718ef2ee5d0SMichal Meloun 719ef2ee5d0SMichal Meloun if (flags & CLK_SET_DRYRUN) { 720ef2ee5d0SMichal Meloun if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && 721ef2ee5d0SMichal Meloun (*fout != (((fin / m) * n) /p))) 722ef2ee5d0SMichal Meloun return (ERANGE); 723ef2ee5d0SMichal Meloun 724ef2ee5d0SMichal Meloun *fout = ((fin / m) * n) /p; 7256f1eb305SMichal Meloun 726ef2ee5d0SMichal Meloun return (0); 727ef2ee5d0SMichal Meloun } 728ef2ee5d0SMichal Meloun 729ef2ee5d0SMichal Meloun pll_disable(sc); 730ef2ee5d0SMichal Meloun 731ef2ee5d0SMichal Meloun /* take pll out of IDDQ */ 732ef2ee5d0SMichal Meloun if (sc->iddq_reg != 0) 733ef2ee5d0SMichal Meloun MD4(sc, sc->iddq_reg, sc->iddq_mask, 0); 734ef2ee5d0SMichal Meloun 735ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 736ef2ee5d0SMichal Meloun reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width); 737ef2ee5d0SMichal Meloun reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width); 738ef2ee5d0SMichal Meloun reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift, 739ef2ee5d0SMichal Meloun mnp_bits->p_width); 740ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 741ef2ee5d0SMichal Meloun 742ef2ee5d0SMichal Meloun /* Enable PLL. */ 743ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 744ef2ee5d0SMichal Meloun reg |= PLL_BASE_ENABLE; 745ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 746ef2ee5d0SMichal Meloun 747ef2ee5d0SMichal Meloun /* Enable lock detection. */ 748ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 749ef2ee5d0SMichal Meloun reg |= sc->lock_enable; 750ef2ee5d0SMichal Meloun WR4(sc, sc->misc_reg, reg); 751ef2ee5d0SMichal Meloun 752ef2ee5d0SMichal Meloun rv = wait_for_lock(sc); 753ef2ee5d0SMichal Meloun if (rv != 0) { 754ef2ee5d0SMichal Meloun /* Disable PLL */ 755ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 756ef2ee5d0SMichal Meloun reg &= ~PLL_BASE_ENABLE; 757ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 758ef2ee5d0SMichal Meloun return (rv); 759ef2ee5d0SMichal Meloun } 760ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 761ef2ee5d0SMichal Meloun 762ef2ee5d0SMichal Meloun pll_enable(sc); 763ef2ee5d0SMichal Meloun *fout = ((fin / m) * n) / p; 764ef2ee5d0SMichal Meloun return 0; 765ef2ee5d0SMichal Meloun } 766ef2ee5d0SMichal Meloun 767ef2ee5d0SMichal Meloun static int 768ef2ee5d0SMichal Meloun plla_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 769ef2ee5d0SMichal Meloun { 770ef2ee5d0SMichal Meloun uint32_t m, n, p; 771ef2ee5d0SMichal Meloun 772ef2ee5d0SMichal Meloun p = 1; 773ef2ee5d0SMichal Meloun m = 5; 774ef2ee5d0SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 775ef2ee5d0SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 776ef2ee5d0SMichal Meloun return (pll_set_std(sc, fin, fout, flags, m, n, p)); 777ef2ee5d0SMichal Meloun } 778ef2ee5d0SMichal Meloun 779ef2ee5d0SMichal Meloun static int 780ef2ee5d0SMichal Meloun pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 781ef2ee5d0SMichal Meloun { 782ef2ee5d0SMichal Meloun uint32_t m, n, p; 783ef2ee5d0SMichal Meloun 784ef2ee5d0SMichal Meloun p = 2; 785ef2ee5d0SMichal Meloun m = 1; 786ef2ee5d0SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 787ef2ee5d0SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 788ef2ee5d0SMichal Meloun return (pll_set_std( sc, fin, fout, flags, m, n, p)); 789ef2ee5d0SMichal Meloun } 790ef2ee5d0SMichal Meloun 7916f1eb305SMichal Meloun /* 7926f1eb305SMichal Meloun * PLLD2 is used as source for pixel clock for HDMI. 7936f1eb305SMichal Meloun * We must be able to set it frequency very flexibly and 7946f1eb305SMichal Meloun * precisely (within 5% tolerance limit allowed by HDMI specs). 7956f1eb305SMichal Meloun * 7966f1eb305SMichal Meloun * For this reason, it is necessary to search the full state space. 7976f1eb305SMichal Meloun * Fortunately, thanks to early cycle terminations, performance 7986f1eb305SMichal Meloun * is within acceptable limits. 7996f1eb305SMichal Meloun */ 8006f1eb305SMichal Meloun #define PLLD2_PFD_MIN 12000000 /* 12 MHz */ 8016f1eb305SMichal Meloun #define PLLD2_PFD_MAX 38000000 /* 38 MHz */ 8026f1eb305SMichal Meloun #define PLLD2_VCO_MIN 600000000 /* 600 MHz */ 8036f1eb305SMichal Meloun #define PLLD2_VCO_MAX 1200000000 /* 1.2 GHz */ 8046f1eb305SMichal Meloun 805ef2ee5d0SMichal Meloun static int 806ef2ee5d0SMichal Meloun plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 807ef2ee5d0SMichal Meloun { 808ef2ee5d0SMichal Meloun uint32_t m, n, p; 8096f1eb305SMichal Meloun uint32_t best_m, best_n, best_p; 8106f1eb305SMichal Meloun uint64_t vco, pfd; 8116f1eb305SMichal Meloun int64_t err, best_err; 8126f1eb305SMichal Meloun struct mnp_bits *mnp_bits; 8136f1eb305SMichal Meloun struct pdiv_table *tbl; 8146f1eb305SMichal Meloun int p_idx, rv; 815ef2ee5d0SMichal Meloun 8166f1eb305SMichal Meloun mnp_bits = &sc->mnp_bits; 8176f1eb305SMichal Meloun tbl = sc->pdiv_table; 8186f1eb305SMichal Meloun best_err = INT64_MAX; 8196f1eb305SMichal Meloun 8206f1eb305SMichal Meloun for (p_idx = 0; tbl[p_idx].divider != 0; p_idx++) { 8216f1eb305SMichal Meloun p = tbl[p_idx].divider; 8226f1eb305SMichal Meloun 8236f1eb305SMichal Meloun /* Check constraints */ 8246f1eb305SMichal Meloun vco = *fout * p; 8256f1eb305SMichal Meloun if (vco < PLLD2_VCO_MIN) 8266f1eb305SMichal Meloun continue; 8276f1eb305SMichal Meloun if (vco > PLLD2_VCO_MAX) 8286f1eb305SMichal Meloun break; 8296f1eb305SMichal Meloun 8306f1eb305SMichal Meloun for (m = 1; m < (1 << mnp_bits->m_width); m++) { 831ef2ee5d0SMichal Meloun n = (*fout * p * m + fin / 2) / fin; 8326f1eb305SMichal Meloun 8336f1eb305SMichal Meloun /* Check constraints */ 8346f1eb305SMichal Meloun if (n == 0) 8356f1eb305SMichal Meloun continue; 8366f1eb305SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 8376f1eb305SMichal Meloun break; 8386f1eb305SMichal Meloun vco = (fin * n) / m; 8396f1eb305SMichal Meloun if (vco > PLLD2_VCO_MAX || vco < PLLD2_VCO_MIN) 8406f1eb305SMichal Meloun continue; 8416f1eb305SMichal Meloun pfd = fin / m; 8426f1eb305SMichal Meloun if (pfd > PLLD2_PFD_MAX || vco < PLLD2_PFD_MIN) 8436f1eb305SMichal Meloun continue; 8446f1eb305SMichal Meloun 8456f1eb305SMichal Meloun /* Constraints passed, save best result */ 8466f1eb305SMichal Meloun err = *fout - vco / p; 8476f1eb305SMichal Meloun if (err < 0) 8486f1eb305SMichal Meloun err = -err; 8496f1eb305SMichal Meloun if (err < best_err) { 8506f1eb305SMichal Meloun best_err = err; 8516f1eb305SMichal Meloun best_p = p; 8526f1eb305SMichal Meloun best_m = m; 8536f1eb305SMichal Meloun best_n = n; 854ef2ee5d0SMichal Meloun } 8556f1eb305SMichal Meloun if (err == 0) 8566f1eb305SMichal Meloun goto done; 8576f1eb305SMichal Meloun } 8586f1eb305SMichal Meloun } 8596f1eb305SMichal Meloun done: 8606f1eb305SMichal Meloun /* 8616f1eb305SMichal Meloun * HDMI specification allows 5% pixel clock tolerance, 8626f1eb305SMichal Meloun * we will by a slightly stricter 8636f1eb305SMichal Meloun */ 8646f1eb305SMichal Meloun if (best_err > ((*fout * 100) / 4)) 8656f1eb305SMichal Meloun return (ERANGE); 866ef2ee5d0SMichal Meloun 8676f1eb305SMichal Meloun if (flags & CLK_SET_DRYRUN) 8686f1eb305SMichal Meloun return (0); 8696f1eb305SMichal Meloun rv = pll_set_std(sc, fin, fout, flags, best_m, best_n, best_p); 8706f1eb305SMichal Meloun /* XXXX Panic for rv == ERANGE ? */ 8716f1eb305SMichal Meloun return (rv); 8726f1eb305SMichal Meloun } 873ef2ee5d0SMichal Meloun 874ef2ee5d0SMichal Meloun static int 875ef2ee5d0SMichal Meloun pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 876ef2ee5d0SMichal Meloun { 877ef2ee5d0SMichal Meloun uint32_t m, n, p; 878ef2ee5d0SMichal Meloun 879ef2ee5d0SMichal Meloun m = 1; 880ef2ee5d0SMichal Meloun p = 1; 881ef2ee5d0SMichal Meloun n = *fout * p * m / fin; 8827961a970SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 883ef2ee5d0SMichal Meloun return (pll_set_std(sc, fin, fout, flags, m, n, p)); 884ef2ee5d0SMichal Meloun } 885ef2ee5d0SMichal Meloun 886ef2ee5d0SMichal Meloun static int 887ef2ee5d0SMichal Meloun pllx_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 888ef2ee5d0SMichal Meloun { 889ef2ee5d0SMichal Meloun uint32_t reg; 890ef2ee5d0SMichal Meloun uint32_t m, n, p; 891ef2ee5d0SMichal Meloun struct mnp_bits *mnp_bits; 892ef2ee5d0SMichal Meloun int rv; 893ef2ee5d0SMichal Meloun 894ef2ee5d0SMichal Meloun mnp_bits = &sc->mnp_bits; 895ef2ee5d0SMichal Meloun 896ef2ee5d0SMichal Meloun p = 1; 897ef2ee5d0SMichal Meloun m = 1; 898ef2ee5d0SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 899ef2ee5d0SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 900ef2ee5d0SMichal Meloun 901ef2ee5d0SMichal Meloun if (m >= (1 << mnp_bits->m_width)) 902ef2ee5d0SMichal Meloun return (ERANGE); 903ef2ee5d0SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 904ef2ee5d0SMichal Meloun return (ERANGE); 905ef2ee5d0SMichal Meloun if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width)) 906ef2ee5d0SMichal Meloun return (ERANGE); 907ef2ee5d0SMichal Meloun 908ef2ee5d0SMichal Meloun if (flags & CLK_SET_DRYRUN) { 909ef2ee5d0SMichal Meloun if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && 910ef2ee5d0SMichal Meloun (*fout != (((fin / m) * n) /p))) 911ef2ee5d0SMichal Meloun return (ERANGE); 912ef2ee5d0SMichal Meloun *fout = ((fin / m) * n) /p; 913ef2ee5d0SMichal Meloun return (0); 914ef2ee5d0SMichal Meloun } 915ef2ee5d0SMichal Meloun 916b7997839SMichal Meloun /* PLLX doesn't have bypass, disable it first. */ 917ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 918b7997839SMichal Meloun reg &= ~PLL_BASE_ENABLE; 919ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 920ef2ee5d0SMichal Meloun 921ef2ee5d0SMichal Meloun /* Set PLL. */ 922ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 923ef2ee5d0SMichal Meloun reg = set_masked(reg, m, PLL_BASE_DIVM_SHIFT, mnp_bits->m_width); 924ef2ee5d0SMichal Meloun reg = set_masked(reg, n, PLL_BASE_DIVN_SHIFT, mnp_bits->n_width); 925ef2ee5d0SMichal Meloun reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift, 926ef2ee5d0SMichal Meloun mnp_bits->p_width); 927ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 928ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 929ef2ee5d0SMichal Meloun DELAY(100); 930ef2ee5d0SMichal Meloun 931b7997839SMichal Meloun /* Enable lock detection. */ 932b7997839SMichal Meloun RD4(sc, sc->misc_reg, ®); 933b7997839SMichal Meloun reg |= sc->lock_enable; 934b7997839SMichal Meloun WR4(sc, sc->misc_reg, reg); 935b7997839SMichal Meloun 936ef2ee5d0SMichal Meloun /* Enable PLL. */ 937ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 938ef2ee5d0SMichal Meloun reg |= PLL_BASE_ENABLE; 939ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 940ef2ee5d0SMichal Meloun 941ef2ee5d0SMichal Meloun rv = wait_for_lock(sc); 942ef2ee5d0SMichal Meloun if (rv != 0) { 943ef2ee5d0SMichal Meloun /* Disable PLL */ 944ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 945ef2ee5d0SMichal Meloun reg &= ~PLL_BASE_ENABLE; 946ef2ee5d0SMichal Meloun WR4(sc, sc->base_reg, reg); 947ef2ee5d0SMichal Meloun return (rv); 948ef2ee5d0SMichal Meloun } 949ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 950ef2ee5d0SMichal Meloun 951ef2ee5d0SMichal Meloun *fout = ((fin / m) * n) / p; 952ef2ee5d0SMichal Meloun return (0); 953ef2ee5d0SMichal Meloun } 954ef2ee5d0SMichal Meloun 955ef2ee5d0SMichal Meloun static int 956ef2ee5d0SMichal Meloun tegra124_pll_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout, 957ef2ee5d0SMichal Meloun int flags, int *stop) 958ef2ee5d0SMichal Meloun { 959ef2ee5d0SMichal Meloun *stop = 1; 960ef2ee5d0SMichal Meloun int rv; 961ef2ee5d0SMichal Meloun struct pll_sc *sc; 962ef2ee5d0SMichal Meloun 963ef2ee5d0SMichal Meloun sc = clknode_get_softc(clknode); 9646f1eb305SMichal Meloun dprintf("%s: %s requested freq: %llu, input freq: %llu\n", __func__, 9656f1eb305SMichal Meloun clknode_get_name(clknode), *fout, fin); 966ef2ee5d0SMichal Meloun switch (sc->type) { 967ef2ee5d0SMichal Meloun case PLL_A: 968ef2ee5d0SMichal Meloun rv = plla_set_freq(sc, fin, fout, flags); 969ef2ee5d0SMichal Meloun break; 970ef2ee5d0SMichal Meloun case PLL_C: 971ef2ee5d0SMichal Meloun rv = pllc_set_freq(sc, fin, fout, flags); 972ef2ee5d0SMichal Meloun break; 973ef2ee5d0SMichal Meloun case PLL_D2: 974ef2ee5d0SMichal Meloun rv = plld2_set_freq(sc, fin, fout, flags); 975ef2ee5d0SMichal Meloun break; 976ef2ee5d0SMichal Meloun 977ef2ee5d0SMichal Meloun case PLL_REFE: 978ef2ee5d0SMichal Meloun rv = pllrefe_set_freq(sc, fin, fout, flags); 979ef2ee5d0SMichal Meloun break; 980ef2ee5d0SMichal Meloun 981ef2ee5d0SMichal Meloun case PLL_X: 982ef2ee5d0SMichal Meloun rv = pllx_set_freq(sc, fin, fout, flags); 983ef2ee5d0SMichal Meloun break; 984ef2ee5d0SMichal Meloun 985ef2ee5d0SMichal Meloun case PLL_U: 986ef2ee5d0SMichal Meloun if (*fout == 480000000) /* PLLU is fixed to 480 MHz */ 987ef2ee5d0SMichal Meloun rv = 0; 988ef2ee5d0SMichal Meloun else 989ef2ee5d0SMichal Meloun rv = ERANGE; 990ef2ee5d0SMichal Meloun break; 991ef2ee5d0SMichal Meloun default: 992ef2ee5d0SMichal Meloun rv = ENXIO; 993ef2ee5d0SMichal Meloun break; 994ef2ee5d0SMichal Meloun } 9957961a970SMichal Meloun 996ef2ee5d0SMichal Meloun return (rv); 997ef2ee5d0SMichal Meloun } 998ef2ee5d0SMichal Meloun 999ef2ee5d0SMichal Meloun static int 1000ef2ee5d0SMichal Meloun tegra124_pll_init(struct clknode *clk, device_t dev) 1001ef2ee5d0SMichal Meloun { 1002ef2ee5d0SMichal Meloun struct pll_sc *sc; 1003ef2ee5d0SMichal Meloun uint32_t reg; 1004ef2ee5d0SMichal Meloun 1005ef2ee5d0SMichal Meloun sc = clknode_get_softc(clk); 1006ef2ee5d0SMichal Meloun 1007ef2ee5d0SMichal Meloun /* If PLL is enabled, enable lock detect too. */ 1008ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 1009ef2ee5d0SMichal Meloun if (reg & PLL_BASE_ENABLE) { 1010ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, ®); 1011ef2ee5d0SMichal Meloun reg |= sc->lock_enable; 1012ef2ee5d0SMichal Meloun WR4(sc, sc->misc_reg, reg); 1013ef2ee5d0SMichal Meloun } 10147961a970SMichal Meloun if (sc->type == PLL_REFE) { 10157961a970SMichal Meloun RD4(sc, sc->misc_reg, ®); 10167961a970SMichal Meloun reg &= ~(1 << 29); /* Diasble lock override */ 10177961a970SMichal Meloun WR4(sc, sc->misc_reg, reg); 10187961a970SMichal Meloun } 1019ef2ee5d0SMichal Meloun 1020ef2ee5d0SMichal Meloun clknode_init_parent_idx(clk, 0); 1021ef2ee5d0SMichal Meloun return(0); 1022ef2ee5d0SMichal Meloun } 1023ef2ee5d0SMichal Meloun 1024ef2ee5d0SMichal Meloun static int 1025ef2ee5d0SMichal Meloun tegra124_pll_recalc(struct clknode *clk, uint64_t *freq) 1026ef2ee5d0SMichal Meloun { 1027ef2ee5d0SMichal Meloun struct pll_sc *sc; 1028ef2ee5d0SMichal Meloun uint32_t m, n, p, pr; 1029ef2ee5d0SMichal Meloun uint32_t reg, misc_reg; 1030ef2ee5d0SMichal Meloun 1031ef2ee5d0SMichal Meloun sc = clknode_get_softc(clk); 1032ef2ee5d0SMichal Meloun 1033ef2ee5d0SMichal Meloun RD4(sc, sc->base_reg, ®); 1034ef2ee5d0SMichal Meloun RD4(sc, sc->misc_reg, &misc_reg); 1035ef2ee5d0SMichal Meloun 1036ef2ee5d0SMichal Meloun get_divisors(sc, &m, &n, &pr); 1037ef2ee5d0SMichal Meloun if (sc->type != PLL_E) 1038ef2ee5d0SMichal Meloun p = reg_to_pdiv(sc, pr); 1039ef2ee5d0SMichal Meloun else 1040ef2ee5d0SMichal Meloun p = 2 * (pr - 1); 1041ef2ee5d0SMichal Meloun 1042ef2ee5d0SMichal Meloun dprintf("%s: %s (0x%08x, 0x%08x) - m: %d, n: %d, p: %d (%d): " 1043ef2ee5d0SMichal Meloun "e: %d, r: %d, o: %d - %s\n", __func__, 1044ef2ee5d0SMichal Meloun clknode_get_name(clk), reg, misc_reg, m, n, p, pr, 1045ef2ee5d0SMichal Meloun (reg >> 30) & 1, (reg >> 29) & 1, (reg >> 28) & 1, 10464b9b6a50SJohn Baldwin is_locked(sc) ? "locked" : "unlocked"); 1047ef2ee5d0SMichal Meloun 1048ef2ee5d0SMichal Meloun if ((m == 0) || (n == 0) || (p == 0)) { 1049ef2ee5d0SMichal Meloun *freq = 0; 1050ef2ee5d0SMichal Meloun return (EINVAL); 1051ef2ee5d0SMichal Meloun } 1052ef2ee5d0SMichal Meloun *freq = ((*freq / m) * n) / p; 1053ef2ee5d0SMichal Meloun return (0); 1054ef2ee5d0SMichal Meloun } 1055ef2ee5d0SMichal Meloun 1056ef2ee5d0SMichal Meloun static int 1057ef2ee5d0SMichal Meloun pll_register(struct clkdom *clkdom, struct clk_pll_def *clkdef) 1058ef2ee5d0SMichal Meloun { 1059ef2ee5d0SMichal Meloun struct clknode *clk; 1060ef2ee5d0SMichal Meloun struct pll_sc *sc; 1061ef2ee5d0SMichal Meloun 1062ef2ee5d0SMichal Meloun clk = clknode_create(clkdom, &tegra124_pll_class, &clkdef->clkdef); 1063ef2ee5d0SMichal Meloun if (clk == NULL) 1064ef2ee5d0SMichal Meloun return (ENXIO); 1065ef2ee5d0SMichal Meloun 1066ef2ee5d0SMichal Meloun sc = clknode_get_softc(clk); 1067ef2ee5d0SMichal Meloun sc->clkdev = clknode_get_device(clk); 1068ef2ee5d0SMichal Meloun sc->type = clkdef->type; 1069ef2ee5d0SMichal Meloun sc->base_reg = clkdef->base_reg; 1070ef2ee5d0SMichal Meloun sc->misc_reg = clkdef->misc_reg; 1071ef2ee5d0SMichal Meloun sc->lock_mask = clkdef->lock_mask; 1072ef2ee5d0SMichal Meloun sc->lock_enable = clkdef->lock_enable; 1073ef2ee5d0SMichal Meloun sc->iddq_reg = clkdef->iddq_reg; 1074ef2ee5d0SMichal Meloun sc->iddq_mask = clkdef->iddq_mask; 1075ef2ee5d0SMichal Meloun sc->flags = clkdef->flags; 1076ef2ee5d0SMichal Meloun sc->pdiv_table = clkdef->pdiv_table; 1077ef2ee5d0SMichal Meloun sc->mnp_bits = clkdef->mnp_bits; 1078ef2ee5d0SMichal Meloun clknode_register(clkdom, clk); 1079ef2ee5d0SMichal Meloun return (0); 1080ef2ee5d0SMichal Meloun } 1081ef2ee5d0SMichal Meloun 1082ef2ee5d0SMichal Meloun static void config_utmi_pll(struct tegra124_car_softc *sc) 1083ef2ee5d0SMichal Meloun { 1084ef2ee5d0SMichal Meloun uint32_t reg; 1085ef2ee5d0SMichal Meloun /* 1086ef2ee5d0SMichal Meloun * XXX Simplified UTMIP settings for 12MHz base clock. 1087ef2ee5d0SMichal Meloun */ 1088ef2ee5d0SMichal Meloun #define ENABLE_DELAY_COUNT 0x02 1089ef2ee5d0SMichal Meloun #define STABLE_COUNT 0x2F 1090ef2ee5d0SMichal Meloun #define ACTIVE_DELAY_COUNT 0x04 1091ef2ee5d0SMichal Meloun #define XTAL_FREQ_COUNT 0x76 1092ef2ee5d0SMichal Meloun 1093ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG2, ®); 1094ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); 1095ef2ee5d0SMichal Meloun reg |= UTMIP_PLL_CFG2_STABLE_COUNT(STABLE_COUNT); 1096ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); 1097ef2ee5d0SMichal Meloun reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(ACTIVE_DELAY_COUNT); 1098ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; 1099ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; 1100ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; 1101ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG2, reg); 1102ef2ee5d0SMichal Meloun 1103ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®); 1104ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); 1105ef2ee5d0SMichal Meloun reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(ENABLE_DELAY_COUNT); 1106ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); 1107ef2ee5d0SMichal Meloun reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(XTAL_FREQ_COUNT); 1108ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; 1109ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; 1110ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP; 1111ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; 1112ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg); 1113ef2ee5d0SMichal Meloun 1114ef2ee5d0SMichal Meloun /* Prepare UTMIP requencer. */ 1115ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1116ef2ee5d0SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; 1117ef2ee5d0SMichal Meloun reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; 1118ef2ee5d0SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE; 1119ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1120ef2ee5d0SMichal Meloun 1121ef2ee5d0SMichal Meloun /* Powerup UTMIP. */ 1122ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®); 1123ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; 1124ef2ee5d0SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; 1125ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg); 1126ef2ee5d0SMichal Meloun DELAY(10); 1127ef2ee5d0SMichal Meloun 1128ef2ee5d0SMichal Meloun /* SW override for UTMIPLL */ 1129ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1130ef2ee5d0SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL; 1131ef2ee5d0SMichal Meloun reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; 1132ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1133ef2ee5d0SMichal Meloun DELAY(10); 1134ef2ee5d0SMichal Meloun 1135ef2ee5d0SMichal Meloun /* HW control of UTMIPLL. */ 1136ef2ee5d0SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1137ef2ee5d0SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; 1138ef2ee5d0SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1139ef2ee5d0SMichal Meloun } 1140ef2ee5d0SMichal Meloun 1141ef2ee5d0SMichal Meloun void 1142ef2ee5d0SMichal Meloun tegra124_init_plls(struct tegra124_car_softc *sc) 1143ef2ee5d0SMichal Meloun { 1144ef2ee5d0SMichal Meloun int i, rv; 1145ef2ee5d0SMichal Meloun 1146ef2ee5d0SMichal Meloun for (i = 0; i < nitems(pll_clks); i++) { 1147ef2ee5d0SMichal Meloun rv = pll_register(sc->clkdom, pll_clks + i); 1148ef2ee5d0SMichal Meloun if (rv != 0) 1149ef2ee5d0SMichal Meloun panic("pll_register failed"); 1150ef2ee5d0SMichal Meloun } 1151ef2ee5d0SMichal Meloun config_utmi_pll(sc); 1152ef2ee5d0SMichal Meloun 1153ef2ee5d0SMichal Meloun } 1154