1e9034789SMichal Meloun /*- 2e9034789SMichal Meloun * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3e9034789SMichal Meloun * 4e9034789SMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 5e9034789SMichal Meloun * 6e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without 7e9034789SMichal Meloun * modification, are permitted provided that the following conditions 8e9034789SMichal Meloun * are met: 9e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright 10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer. 11e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 12e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the 13e9034789SMichal Meloun * documentation and/or other materials provided with the distribution. 14e9034789SMichal Meloun * 15e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e9034789SMichal Meloun * SUCH DAMAGE. 26e9034789SMichal Meloun */ 27e9034789SMichal Meloun 28e9034789SMichal Meloun #include <sys/cdefs.h> 29e9034789SMichal Meloun __FBSDID("$FreeBSD$"); 30e9034789SMichal Meloun 31e9034789SMichal Meloun #include <sys/param.h> 32e9034789SMichal Meloun #include <sys/systm.h> 33e9034789SMichal Meloun #include <sys/bus.h> 34e9034789SMichal Meloun #include <sys/lock.h> 35e9034789SMichal Meloun #include <sys/mutex.h> 36e9034789SMichal Meloun #include <sys/rman.h> 37e9034789SMichal Meloun 38e9034789SMichal Meloun #include <machine/bus.h> 39e9034789SMichal Meloun 40e9034789SMichal Meloun #include <dev/extres/clk/clk_div.h> 41e9034789SMichal Meloun #include <dev/extres/clk/clk_fixed.h> 42e9034789SMichal Meloun #include <dev/extres/clk/clk_gate.h> 43e9034789SMichal Meloun #include <dev/extres/clk/clk_mux.h> 44e9034789SMichal Meloun 45c38fe878SEmmanuel Vadot #include <dt-bindings/clock/tegra210-car.h> 46e9034789SMichal Meloun #include "tegra210_car.h" 47e9034789SMichal Meloun 48e9034789SMichal Meloun #if 0 49e9034789SMichal Meloun #define dprintf(...) printf(__VA_ARGS__) 50e9034789SMichal Meloun #else 51e9034789SMichal Meloun #define dprintf(...) 52e9034789SMichal Meloun #endif 53e9034789SMichal Meloun 54e9034789SMichal Meloun /* All PLLs. */ 55e9034789SMichal Meloun enum pll_type { 56e9034789SMichal Meloun PLL_M, 57e9034789SMichal Meloun PLL_MB, 58e9034789SMichal Meloun PLL_X, 59e9034789SMichal Meloun PLL_C, 60e9034789SMichal Meloun PLL_C2, 61e9034789SMichal Meloun PLL_C3, 62e9034789SMichal Meloun PLL_C4, 63e9034789SMichal Meloun PLL_P, 64e9034789SMichal Meloun PLL_A, 65e9034789SMichal Meloun PLL_A1, 66e9034789SMichal Meloun PLL_U, 67e9034789SMichal Meloun PLL_D, 68e9034789SMichal Meloun PLL_D2, 69e9034789SMichal Meloun PLL_DP, 70e9034789SMichal Meloun PLL_E, 71e9034789SMichal Meloun PLL_REFE}; 72e9034789SMichal Meloun /* Flags for PLLs */ 73e9034789SMichal Meloun 74e9034789SMichal Meloun #define PLL_FLAG_PDIV_POWER2 0x01 /* P Divider is 2^n */ 75e9034789SMichal Meloun #define PLL_FLAG_VCO_OUT 0x02 /* Output VCO directly */ 76e9034789SMichal Meloun #define PLL_FLAG_HAVE_SDM 0x04 /* Have SDM implemented */ 77e9034789SMichal Meloun #define PLL_FLAG_HAVE_SDA 0x04 /* Have SDA implemented */ 78e9034789SMichal Meloun 79e9034789SMichal Meloun /* Common base register bits. */ 80e9034789SMichal Meloun #define PLL_BASE_BYPASS (1U << 31) 81e9034789SMichal Meloun #define PLL_BASE_ENABLE (1 << 30) 82e9034789SMichal Meloun #define PLL_BASE_REFDISABLE (1 << 29) 83e9034789SMichal Meloun #define PLL_BASE_LOCK (1 << 27) 84e9034789SMichal Meloun 85e9034789SMichal Meloun #define PLLREFE_MISC_LOCK (1 << 27) 86e9034789SMichal Meloun 87e9034789SMichal Meloun #define PLL_MISC_LOCK_ENABLE (1 << 18) 88e9034789SMichal Meloun #define PLLM_LOCK_ENABLE (1 << 4) 89e9034789SMichal Meloun #define PLLMB_LOCK_ENABLE (1 << 16) 90e9034789SMichal Meloun #define PLLC_LOCK_ENABLE (1 << 24) 91e9034789SMichal Meloun #define PLLC4_LOCK_ENABLE (1 << 30) 92e9034789SMichal Meloun #define PLLA_LOCK_ENABLE (1 << 28) 93e9034789SMichal Meloun #define PLLD2_LOCK_ENABLE (1 << 30) 94e9034789SMichal Meloun #define PLLU_LOCK_ENABLE (1 << 29) 95e9034789SMichal Meloun #define PLLREFE_LOCK_ENABLE (1 << 30) 96e9034789SMichal Meloun #define PLLPD_LOCK_ENABLE (1 << 30) 97e9034789SMichal Meloun #define PLLE_LOCK_ENABLE (1 << 9) 98e9034789SMichal Meloun 99e9034789SMichal Meloun #define PLLM_IDDQ_BIT 5 100e9034789SMichal Meloun #define PLLMB_IDDQ_BIT 17 101e9034789SMichal Meloun #define PLLC_IDDQ_BIT 27 102e9034789SMichal Meloun #define PLLC4_IDDQ_BIT 18 103e9034789SMichal Meloun #define PLLP_IDDQ_BIT 3 104e9034789SMichal Meloun #define PLLA_IDDQ_BIT 25 105e9034789SMichal Meloun #define PLLA1_IDDQ_BIT 27 106e9034789SMichal Meloun #define PLLU_IDDQ_BIT 31 107e9034789SMichal Meloun #define PLLD_IDDQ_BIT 20 108e9034789SMichal Meloun #define PLLD2_IDDQ_BIT 18 109e9034789SMichal Meloun #define PLLX_IDDQ_BIT 3 110e9034789SMichal Meloun #define PLLREFE_IDDQ_BIT 24 111e9034789SMichal Meloun #define PLLDP_IDDQ_BIT 18 112e9034789SMichal Meloun 113e9034789SMichal Meloun 114e9034789SMichal Meloun #define PLL_LOCK_TIMEOUT 5000 115e9034789SMichal Meloun 116e9034789SMichal Meloun /* Post divider <-> register value mapping. */ 117e9034789SMichal Meloun struct pdiv_table { 118e9034789SMichal Meloun uint32_t divider; /* real divider */ 119e9034789SMichal Meloun uint32_t value; /* register value */ 120e9034789SMichal Meloun }; 121e9034789SMichal Meloun 122e9034789SMichal Meloun /* Bits definition of M, N and P fields. */ 123e9034789SMichal Meloun struct mnp_bits { 124e9034789SMichal Meloun uint32_t m_width; 125e9034789SMichal Meloun uint32_t n_width; 126e9034789SMichal Meloun uint32_t p_width; 127e9034789SMichal Meloun uint32_t m_shift; 128e9034789SMichal Meloun uint32_t n_shift; 129e9034789SMichal Meloun uint32_t p_shift; 130e9034789SMichal Meloun }; 131e9034789SMichal Meloun 132e9034789SMichal Meloun struct clk_pll_def { 133e9034789SMichal Meloun struct clknode_init_def clkdef; 134e9034789SMichal Meloun enum pll_type type; 135e9034789SMichal Meloun uint32_t base_reg; 136e9034789SMichal Meloun uint32_t misc_reg; 137e9034789SMichal Meloun uint32_t lock_enable; 138e9034789SMichal Meloun uint32_t iddq_reg; 139e9034789SMichal Meloun uint32_t iddq_mask; 140e9034789SMichal Meloun uint32_t flags; 141e9034789SMichal Meloun struct pdiv_table *pdiv_table; 142e9034789SMichal Meloun struct mnp_bits mnp_bits; 143e9034789SMichal Meloun }; 144e9034789SMichal Meloun 145e9034789SMichal Meloun #define PLIST(x) static const char *x[] 146e9034789SMichal Meloun 147e9034789SMichal Meloun #define PLL(_id, cname, pname) \ 148e9034789SMichal Meloun .clkdef.id = _id, \ 149e9034789SMichal Meloun .clkdef.name = cname, \ 150e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){pname}, \ 151e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 152e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS 153e9034789SMichal Meloun 154e9034789SMichal Meloun /* multiplexer for pll sources. */ 155e9034789SMichal Meloun #define MUX(_id, cname, plists, o, s, w) \ 156e9034789SMichal Meloun { \ 157e9034789SMichal Meloun .clkdef.id = _id, \ 158e9034789SMichal Meloun .clkdef.name = cname, \ 159e9034789SMichal Meloun .clkdef.parent_names = plists, \ 160e9034789SMichal Meloun .clkdef.parent_cnt = nitems(plists), \ 161e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 162e9034789SMichal Meloun .offset = o, \ 163e9034789SMichal Meloun .shift = s, \ 164e9034789SMichal Meloun .width = w, \ 165e9034789SMichal Meloun } 166e9034789SMichal Meloun 167e9034789SMichal Meloun /* Fractional divider (7.1) for PLL branch. */ 168e9034789SMichal Meloun #define DIV7_1(_id, cname, plist, o, s) \ 169e9034789SMichal Meloun { \ 170e9034789SMichal Meloun .clkdef.id = _id, \ 171e9034789SMichal Meloun .clkdef.name = cname, \ 172e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \ 173e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 174e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 175e9034789SMichal Meloun .offset = o, \ 176e9034789SMichal Meloun .i_shift = (s) + 1, \ 177e9034789SMichal Meloun .i_width = 7, \ 178e9034789SMichal Meloun .f_shift = s, \ 179e9034789SMichal Meloun .f_width = 1, \ 180e9034789SMichal Meloun } 181e9034789SMichal Meloun 182e9034789SMichal Meloun /* P divider (2^n). for PLL branch. */ 183e9034789SMichal Meloun #define DIV5_E(_id, cname, plist, o, s) \ 184e9034789SMichal Meloun { \ 185e9034789SMichal Meloun .clkdef.id = _id, \ 186e9034789SMichal Meloun .clkdef.name = cname, \ 187e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \ 188e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 189e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 190e9034789SMichal Meloun .offset = o, \ 191e9034789SMichal Meloun .i_shift = s, \ 192e9034789SMichal Meloun .i_width = 5, \ 193e9034789SMichal Meloun } 194e9034789SMichal Meloun 195e9034789SMichal Meloun /* P divider (2^n). for PLL branch. */ 196e9034789SMichal Meloun #define DIV_TB(_id, cname, plist, o, s, n, table) \ 197e9034789SMichal Meloun { \ 198e9034789SMichal Meloun .clkdef.id = _id, \ 199e9034789SMichal Meloun .clkdef.name = cname, \ 200e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \ 201e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 202e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 203e9034789SMichal Meloun .div_flags = CLK_DIV_WITH_TABLE | CLK_DIV_ZERO_BASED, \ 204e9034789SMichal Meloun .offset = o, \ 205e9034789SMichal Meloun .i_shift = s, \ 206e9034789SMichal Meloun .i_width = n, \ 207e9034789SMichal Meloun .div_table = table, \ 208e9034789SMichal Meloun } 209e9034789SMichal Meloun 210e9034789SMichal Meloun /* Standard gate. */ 211e9034789SMichal Meloun #define GATE(_id, cname, plist, o, s) \ 212e9034789SMichal Meloun { \ 213e9034789SMichal Meloun .clkdef.id = _id, \ 214e9034789SMichal Meloun .clkdef.name = cname, \ 215e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \ 216e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 217e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 218e9034789SMichal Meloun .offset = o, \ 219e9034789SMichal Meloun .shift = s, \ 220e9034789SMichal Meloun .mask = 1, \ 221e9034789SMichal Meloun .on_value = 1, \ 222e9034789SMichal Meloun .off_value = 0, \ 223e9034789SMichal Meloun } 224e9034789SMichal Meloun /* Gate for PLL branch. */ 225e9034789SMichal Meloun #define GATE_PLL(_id, cname, plist, o, s) \ 226e9034789SMichal Meloun { \ 227e9034789SMichal Meloun .clkdef.id = _id, \ 228e9034789SMichal Meloun .clkdef.name = cname, \ 229e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \ 230e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 231e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 232e9034789SMichal Meloun .offset = o, \ 233e9034789SMichal Meloun .shift = s, \ 234e9034789SMichal Meloun .mask = 3, \ 235e9034789SMichal Meloun .on_value = 3, \ 236e9034789SMichal Meloun .off_value = 0, \ 237e9034789SMichal Meloun } 238e9034789SMichal Meloun 239e9034789SMichal Meloun /* Fixed rate multipier/divider. */ 240e9034789SMichal Meloun #define FACT(_id, cname, pname, _mult, _div) \ 241e9034789SMichal Meloun { \ 242e9034789SMichal Meloun .clkdef.id = _id, \ 243e9034789SMichal Meloun .clkdef.name = cname, \ 244e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){pname}, \ 245e9034789SMichal Meloun .clkdef.parent_cnt = 1, \ 246e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 247e9034789SMichal Meloun .mult = _mult, \ 248e9034789SMichal Meloun .div = _div, \ 249e9034789SMichal Meloun } 250e9034789SMichal Meloun 251e9034789SMichal Meloun static struct pdiv_table qlin_map[] = { 252e9034789SMichal Meloun { 1, 0}, 253e9034789SMichal Meloun { 2, 1}, 254e9034789SMichal Meloun { 3, 2}, 255e9034789SMichal Meloun { 4, 3}, 256e9034789SMichal Meloun { 5, 4}, 257e9034789SMichal Meloun { 6, 5}, 258e9034789SMichal Meloun { 8, 6}, 259e9034789SMichal Meloun { 9, 7}, 260e9034789SMichal Meloun {10, 8}, 261e9034789SMichal Meloun {12, 9}, 262e9034789SMichal Meloun {15, 10}, 263e9034789SMichal Meloun {16, 11}, 264e9034789SMichal Meloun {18, 12}, 265e9034789SMichal Meloun {20, 13}, 266e9034789SMichal Meloun {24, 14}, 267e9034789SMichal Meloun {30, 15}, 268e9034789SMichal Meloun {32, 16}, 269e9034789SMichal Meloun { 0, 0}, 270e9034789SMichal Meloun }; 271e9034789SMichal Meloun 272e9034789SMichal Meloun static struct clk_pll_def pll_clks[] = { 273e9034789SMichal Meloun /* PLLM: 880 MHz Clock source for EMC 2x clock */ 274e9034789SMichal Meloun { 275e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_M, "pllM_out0", "osc"), 276e9034789SMichal Meloun .type = PLL_M, 277e9034789SMichal Meloun .base_reg = PLLM_BASE, 278e9034789SMichal Meloun .misc_reg = PLLM_MISC2, 279e9034789SMichal Meloun .lock_enable = PLLM_LOCK_ENABLE, 280e9034789SMichal Meloun .iddq_reg = PLLM_MISC2, 281e9034789SMichal Meloun .iddq_mask = 1 << PLLM_IDDQ_BIT, 282e9034789SMichal Meloun .pdiv_table = qlin_map, 283e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 20}, 284e9034789SMichal Meloun }, 285e9034789SMichal Meloun /* PLLMB: 880 MHz Clock source for EMC 2x clock */ 286e9034789SMichal Meloun { 287e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_M, "pllMB_out0", "osc"), 288e9034789SMichal Meloun .type = PLL_MB, 289e9034789SMichal Meloun .base_reg = PLLMB_BASE, 290e9034789SMichal Meloun .misc_reg = PLLMB_MISC1, 291e9034789SMichal Meloun .lock_enable = PLLMB_LOCK_ENABLE, 292e9034789SMichal Meloun .iddq_reg = PLLMB_MISC1, 293e9034789SMichal Meloun .iddq_mask = 1 << PLLMB_IDDQ_BIT, 294e9034789SMichal Meloun .pdiv_table = qlin_map, 295e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 20}, 296e9034789SMichal Meloun }, 297e9034789SMichal Meloun /* PLLX: 1GHz Clock source for the fast CPU cluster and the shadow CPU */ 298e9034789SMichal Meloun { 299e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_X, "pllX_out0", "osc_div_clk"), 300e9034789SMichal Meloun .type = PLL_X, 301e9034789SMichal Meloun .base_reg = PLLX_BASE, 302e9034789SMichal Meloun .misc_reg = PLLX_MISC, 303e9034789SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 304e9034789SMichal Meloun .iddq_reg = PLLX_MISC_3, 305e9034789SMichal Meloun .iddq_mask = 1 << PLLX_IDDQ_BIT, 306e9034789SMichal Meloun .pdiv_table = qlin_map, 307e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 20}, 308e9034789SMichal Meloun }, 309e9034789SMichal Meloun /* PLLC: 510 MHz Clock source for camera use */ 310e9034789SMichal Meloun { 311e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_C, "pllC_out0", "osc_div_clk"), 312e9034789SMichal Meloun .type = PLL_C, 313e9034789SMichal Meloun .base_reg = PLLC_BASE, 314e9034789SMichal Meloun .misc_reg = PLLC_MISC_0, 315e9034789SMichal Meloun .iddq_reg = PLLC_MISC_1, 316e9034789SMichal Meloun .iddq_mask = 1 << PLLC_IDDQ_BIT, 317e9034789SMichal Meloun .pdiv_table = qlin_map, 318e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 10, 20}, 319e9034789SMichal Meloun }, 320e9034789SMichal Meloun /* PLLC2: 510 MHz Clock source for SE, VIC, TSECB, NVJPG scaling */ 321e9034789SMichal Meloun { 322e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_C2, "pllC2_out0", "osc_div_clk"), 323e9034789SMichal Meloun .type = PLL_C2, 324e9034789SMichal Meloun .base_reg = PLLC2_BASE, 325e9034789SMichal Meloun .misc_reg = PLLC2_MISC_0, 326e9034789SMichal Meloun .iddq_reg = PLLC2_MISC_1, 327e9034789SMichal Meloun .iddq_mask = 1 << PLLC_IDDQ_BIT, 328e9034789SMichal Meloun .pdiv_table = qlin_map, 329e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 10, 20}, 330e9034789SMichal Meloun }, 331e9034789SMichal Meloun /* PLLC3: 510 MHz Clock source for NVENC, NVDEC scaling */ 332e9034789SMichal Meloun { 333e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_C3, "pllC3_out0", "osc_div_clk"), 334e9034789SMichal Meloun .type = PLL_C3, 335e9034789SMichal Meloun .base_reg = PLLC3_BASE, 336e9034789SMichal Meloun .misc_reg = PLLC3_MISC_0, 337e9034789SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 338e9034789SMichal Meloun .iddq_reg = PLLC3_MISC_1, 339e9034789SMichal Meloun .iddq_mask = 1 << PLLC_IDDQ_BIT, 340e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 10, 20}, 341e9034789SMichal Meloun }, 342e9034789SMichal Meloun /* PLLC4: 600 MHz Clock source for SD/eMMC ans system busses */ 343e9034789SMichal Meloun { 344e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_C4, "pllC4", "pllC4_src"), 345e9034789SMichal Meloun .type = PLL_C4, 346e9034789SMichal Meloun .flags = PLL_FLAG_VCO_OUT, 347e9034789SMichal Meloun .base_reg = PLLC4_BASE, 348e9034789SMichal Meloun .misc_reg = PLLC4_MISC, 349e9034789SMichal Meloun .lock_enable = PLLC4_LOCK_ENABLE, 350e9034789SMichal Meloun .iddq_reg = PLLC4_BASE, 351e9034789SMichal Meloun .iddq_mask = 1 << PLLC4_IDDQ_BIT, 352e9034789SMichal Meloun .pdiv_table = qlin_map, 353e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 19}, 354e9034789SMichal Meloun }, 355e9034789SMichal Meloun /* PLLP: 408 MHz Clock source for most peripherals */ 356e9034789SMichal Meloun { 357e9034789SMichal Meloun /* 358e9034789SMichal Meloun * VCO is directly exposed as pllP_out0, P div is used for 359e9034789SMichal Meloun * pllP_out2 360e9034789SMichal Meloun */ 361e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_P, "pllP_out0", "osc_div_clk"), 362e9034789SMichal Meloun .type = PLL_P, 363e9034789SMichal Meloun .flags = PLL_FLAG_VCO_OUT, 364e9034789SMichal Meloun .base_reg = PLLP_BASE, 365e9034789SMichal Meloun .misc_reg = PLLP_MISC, 366e9034789SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 367e9034789SMichal Meloun .iddq_reg = PLLP_MISC, 368e9034789SMichal Meloun .iddq_mask = 1 << PLLA_IDDQ_BIT, 369e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 10, 20}, 370e9034789SMichal Meloun }, 371e9034789SMichal Meloun /* PLLA: Audio clock for precise codec sampling */ 372e9034789SMichal Meloun { 373e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_A, "pllA", "osc_div_clk"), 374e9034789SMichal Meloun .type = PLL_A, 375e9034789SMichal Meloun .base_reg = PLLA_BASE, 376e9034789SMichal Meloun .misc_reg = PLLA_MISC, 377e9034789SMichal Meloun .lock_enable = PLLA_LOCK_ENABLE, 378e9034789SMichal Meloun .iddq_reg = PLLA_BASE, 379e9034789SMichal Meloun .iddq_mask = 1 << PLLA_IDDQ_BIT, 380e9034789SMichal Meloun .pdiv_table = qlin_map, 381e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 20}, 382e9034789SMichal Meloun }, 383e9034789SMichal Meloun /* PLLA1: Audio clock for ADSP */ 384e9034789SMichal Meloun { 385e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_A1, "pllA1_out0", "osc_div_clk"), 386e9034789SMichal Meloun .type = PLL_A1, 387e9034789SMichal Meloun .base_reg = PLLA1_BASE, 388e9034789SMichal Meloun .misc_reg = PLLA1_MISC_1, 389e9034789SMichal Meloun .iddq_reg = PLLA1_MISC_1, 390e9034789SMichal Meloun .iddq_mask = 1 << PLLA_IDDQ_BIT, 391e9034789SMichal Meloun .pdiv_table = qlin_map, 392e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 20}, 393e9034789SMichal Meloun }, 394e9034789SMichal Meloun /* PLLU: 480 MHz Clock source for USB PHY, provides 12/60/480 MHz */ 395e9034789SMichal Meloun { 396e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_U, "pllU", "osc_div_clk"), 397e9034789SMichal Meloun .type = PLL_U, 398e9034789SMichal Meloun .flags = PLL_FLAG_VCO_OUT | PLL_FLAG_HAVE_SDA, 399e9034789SMichal Meloun .base_reg = PLLU_BASE, 400e9034789SMichal Meloun .misc_reg = PLLU_MISC, 401e9034789SMichal Meloun .lock_enable = PLLU_LOCK_ENABLE, 402e9034789SMichal Meloun .iddq_reg = PLLU_MISC, 403e9034789SMichal Meloun .iddq_mask = 1 << PLLU_IDDQ_BIT, 404e9034789SMichal Meloun .pdiv_table = qlin_map, 405e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 16}, 406e9034789SMichal Meloun }, 407e9034789SMichal Meloun /* PLLD: 594 MHz Clock sources for the DSI and display subsystem */ 408e9034789SMichal Meloun { 409e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_D, "pllD_out", "osc_div_clk"), 410e9034789SMichal Meloun .type = PLL_D, 411e9034789SMichal Meloun .flags = PLL_FLAG_PDIV_POWER2, 412e9034789SMichal Meloun .base_reg = PLLD_BASE, 413e9034789SMichal Meloun .misc_reg = PLLD_MISC, 414e9034789SMichal Meloun .lock_enable = PLL_MISC_LOCK_ENABLE, 415e9034789SMichal Meloun .iddq_reg = PLLA1_MISC_1, 416e9034789SMichal Meloun .iddq_mask = 1 << PLLA_IDDQ_BIT, 417e9034789SMichal Meloun .mnp_bits = {8, 8, 3, 0, 11, 20}, 418e9034789SMichal Meloun }, 419e9034789SMichal Meloun /* PLLD2: 594 MHz Clock sources for the DSI and display subsystem */ 420e9034789SMichal Meloun { 421e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_D2, "pllD2_out", "pllD2_src"), 422e9034789SMichal Meloun .type = PLL_D2, 423e9034789SMichal Meloun .flags = PLL_FLAG_HAVE_SDM, 424e9034789SMichal Meloun .base_reg = PLLD2_BASE, 425e9034789SMichal Meloun .misc_reg = PLLD2_MISC, 426e9034789SMichal Meloun .lock_enable = PLLD2_LOCK_ENABLE, 427e9034789SMichal Meloun .iddq_reg = PLLD2_BASE, 428e9034789SMichal Meloun .iddq_mask = 1 << PLLD_IDDQ_BIT, 429e9034789SMichal Meloun .pdiv_table = qlin_map, 430e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 19}, 431e9034789SMichal Meloun }, 432e9034789SMichal Meloun /* PLLREFE: 624 Mhz*/ 433e9034789SMichal Meloun { 434e9034789SMichal Meloun PLL(0, "pllREFE", "osc_div_clk"), 435e9034789SMichal Meloun .type = PLL_REFE, 436e9034789SMichal Meloun .flags = PLL_FLAG_VCO_OUT, 437e9034789SMichal Meloun .base_reg = PLLREFE_BASE, 438e9034789SMichal Meloun .misc_reg = PLLREFE_MISC, 439e9034789SMichal Meloun .lock_enable = PLLREFE_LOCK_ENABLE, 440e9034789SMichal Meloun .iddq_reg = PLLREFE_MISC, 441e9034789SMichal Meloun .iddq_mask = 1 << PLLREFE_IDDQ_BIT, 442e9034789SMichal Meloun .pdiv_table = qlin_map, 443e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 16}, 444e9034789SMichal Meloun }, 445e9034789SMichal Meloun /* PLLE: 100 MHz reference clock for PCIe/SATA/USB 3.0 (spread spectrum) */ 446e9034789SMichal Meloun { 447e9034789SMichal Meloun PLL(TEGRA210_CLK_PLL_E, "pllE_out0", "pllE_src"), 448e9034789SMichal Meloun .type = PLL_E, 449e9034789SMichal Meloun .base_reg = PLLE_BASE, 450e9034789SMichal Meloun .misc_reg = PLLE_MISC, 451e9034789SMichal Meloun .lock_enable = PLLE_LOCK_ENABLE, 452e9034789SMichal Meloun .pdiv_table = qlin_map, 453e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 24}, 454e9034789SMichal Meloun }, 455e9034789SMichal Meloun /* PLLDP: 270 MHz Clock source fordisplay SOR (spread spectrum) */ 456e9034789SMichal Meloun { 457e9034789SMichal Meloun PLL(0, "pllDP_out0", "pllDP_src"), 458e9034789SMichal Meloun .type = PLL_DP, 459e9034789SMichal Meloun .flags = PLL_FLAG_HAVE_SDM, 460e9034789SMichal Meloun .base_reg = PLLDP_BASE, 461e9034789SMichal Meloun .misc_reg = PLLDP_MISC, 462e9034789SMichal Meloun .lock_enable = PLLPD_LOCK_ENABLE, 463e9034789SMichal Meloun .iddq_reg = PLLDP_BASE, 464e9034789SMichal Meloun .iddq_mask = 1 << PLLDP_IDDQ_BIT, 465e9034789SMichal Meloun .pdiv_table = qlin_map, 466e9034789SMichal Meloun .mnp_bits = {8, 8, 5, 0, 8, 19}, 467e9034789SMichal Meloun }, 468e9034789SMichal Meloun }; 469e9034789SMichal Meloun 470e9034789SMichal Meloun /* Fixed rate dividers. */ 471e9034789SMichal Meloun static struct clk_fixed_def tegra210_pll_fdivs[] = { 472e9034789SMichal Meloun FACT(0, "pllP_UD", "pllP_out0", 1, 1), 473e9034789SMichal Meloun FACT(0, "pllC_UD", "pllC_out0", 1, 1), 474e9034789SMichal Meloun FACT(0, "pllD_UD", "pllD_out0", 1, 1), 475e9034789SMichal Meloun FACT(0, "pllM_UD", "pllM_out0", 1, 1), 476e9034789SMichal Meloun FACT(0, "pllMB_UD", "pllMB_out0", 1, 1), 477e9034789SMichal Meloun FACT(TEGRA210_CLK_PLL_D_OUT0, "pllD_out0", "pllD_out", 1, 2), 478e9034789SMichal Meloun 479e9034789SMichal Meloun FACT(0, "pllC4_out1", "pllC4", 1, 3), 480e9034789SMichal Meloun FACT(0, "pllC4_out2", "pllC4", 1, 5), 481e9034789SMichal Meloun FACT(0, "pllD2_out0", "pllD2_out", 1, 2), 482e9034789SMichal Meloun 483e9034789SMichal Meloun /* Aliases used in super mux. */ 484e9034789SMichal Meloun FACT(0, "pllX_out0_alias", "pllX_out0", 1, 1), 485e9034789SMichal Meloun FACT(0, "dfllCPU_out_alias", "dfllCPU_out", 1, 1), 486e9034789SMichal Meloun }; 487e9034789SMichal Meloun 488e9034789SMichal Meloun /* MUXes for PLL sources. */ 489e9034789SMichal Meloun PLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */ 490e9034789SMichal Meloun PLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"}; 491e9034789SMichal Meloun PLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out0"}; 492e9034789SMichal Meloun static struct clk_mux_def tegra210_pll_sources[] = { 493e9034789SMichal Meloun /* Core clocks. */ 494e9034789SMichal Meloun MUX(0, "pllD2_src", mux_pll_srcs, PLLD2_BASE, 25, 2), 495e9034789SMichal Meloun MUX(0, "pllDP_src", mux_pll_srcs, PLLDP_BASE, 25, 2), 496e9034789SMichal Meloun MUX(0, "pllC4_src", mux_pll_srcs, PLLC4_BASE, 25, 2), 497e9034789SMichal Meloun MUX(0, "pllE_src1", mux_plle_src1, PLLE_AUX, 2, 1), 498e9034789SMichal Meloun MUX(0, "pllE_src", mux_plle_src, PLLE_AUX, 28, 1), 499e9034789SMichal Meloun }; 500e9034789SMichal Meloun 501e9034789SMichal Meloun /* Gates for PLL branches. */ 502e9034789SMichal Meloun static struct clk_gate_def tegra210_pll_gates[] = { 503e9034789SMichal Meloun /* Core clocks. */ 504e9034789SMichal Meloun GATE_PLL(0, "pllC_out1", "pllC_out1_div", PLLC_OUT, 0), 505e9034789SMichal Meloun 506e9034789SMichal Meloun GATE_PLL(0, "pllP_out1", "pllP_out1_div", PLLP_OUTA, 0), 507e9034789SMichal Meloun GATE_PLL(0, "pllP_out3", "pllP_out3_div", PLLP_OUTB, 0), 508e9034789SMichal Meloun GATE_PLL(TEGRA210_CLK_PLL_P_OUT4, "pllP_out4", "pllP_out4_div", PLLP_OUTB, 16), 509e9034789SMichal Meloun GATE_PLL(0, "pllP_out5", "pllP_out5_div", PLLP_OUTC, 16), 510e9034789SMichal Meloun 511e9034789SMichal Meloun GATE_PLL(0, "pllU_out1", "pllU_out1_div", PLLU_OUTA, 0), 512e9034789SMichal Meloun GATE_PLL(0, "pllU_out2", "pllU_out2_div", PLLU_OUTA, 16), 513e9034789SMichal Meloun GATE(0, "pllU_480", "pllU", PLLU_BASE, 22), 514e9034789SMichal Meloun GATE(0, "pllU_60", "pllU_out2", PLLU_BASE, 23), 515e9034789SMichal Meloun GATE(0, "pllU_48", "pllU_out1", PLLU_BASE, 25), 516e9034789SMichal Meloun 517e9034789SMichal Meloun GATE_PLL(0, "pllREFE_out1", "pllREFE_out1_div", PLLREFE_OUT, 0), 518e9034789SMichal Meloun GATE_PLL(0, "pllC4_out3", "pllC4_out3_div", PLLC4_OUT, 0), 519e9034789SMichal Meloun 520e9034789SMichal Meloun GATE_PLL(0, "pllA_out0", "pllA_out0_div", PLLA_OUT, 0), 521e9034789SMichal Meloun }; 522e9034789SMichal Meloun 523e9034789SMichal Meloun struct clk_div_table tegra210_pll_pdiv_tbl[] = { 524e9034789SMichal Meloun /* value , divider */ 525e9034789SMichal Meloun { 0, 1 }, 526e9034789SMichal Meloun { 1, 2 }, 527e9034789SMichal Meloun { 2, 3 }, 528e9034789SMichal Meloun { 3, 4 }, 529e9034789SMichal Meloun { 4, 5 }, 530e9034789SMichal Meloun { 5, 6 }, 531e9034789SMichal Meloun { 6, 8 }, 532e9034789SMichal Meloun { 7, 10 }, 533e9034789SMichal Meloun { 8, 12 }, 534e9034789SMichal Meloun { 9, 16 }, 535e9034789SMichal Meloun {10, 12 }, 536e9034789SMichal Meloun {11, 16 }, 537e9034789SMichal Meloun {12, 20 }, 538e9034789SMichal Meloun {13, 24 }, 539e9034789SMichal Meloun {14, 32 }, 540e9034789SMichal Meloun { 0, 0 }, 541e9034789SMichal Meloun }; 542e9034789SMichal Meloun 543e9034789SMichal Meloun /* Dividers for PLL branches. */ 544e9034789SMichal Meloun static struct clk_div_def tegra210_pll_divs[] = { 545e9034789SMichal Meloun /* Core clocks. */ 546e9034789SMichal Meloun DIV7_1(0, "pllC_out1_div", "pllC_out0", PLLC_OUT, 8), 547e9034789SMichal Meloun 548e9034789SMichal Meloun DIV7_1(0, "pllP_out1_div", "pllP_out0", PLLP_OUTA, 8), 549e9034789SMichal Meloun DIV_TB(0, "pllP_out2", "pllP_out0", PLLP_BASE, 20, 5, tegra210_pll_pdiv_tbl), 550e9034789SMichal Meloun DIV7_1(0, "pllP_out3_div", "pllP_out0", PLLP_OUTB, 8), 551e9034789SMichal Meloun DIV7_1(0, "pllP_out4_div", "pllP_out0", PLLP_OUTB, 24), 552e9034789SMichal Meloun DIV7_1(0, "pllP_out5_div", "pllP_out0", PLLP_OUTC, 24), 553e9034789SMichal Meloun 554e9034789SMichal Meloun DIV_TB(0, "pllU_out0", "pllU", PLLU_BASE, 16, 5, tegra210_pll_pdiv_tbl), 555e9034789SMichal Meloun DIV7_1(0, "pllU_out1_div", "pllU_out0", PLLU_OUTA, 8), 556e9034789SMichal Meloun DIV7_1(0, "pllU_out2_div", "pllU_out0", PLLU_OUTA, 24), 557e9034789SMichal Meloun 558e9034789SMichal Meloun DIV_TB(0, "pllREFE_out0", "pllREFE", PLLREFE_BASE, 16, 5, tegra210_pll_pdiv_tbl), 559e9034789SMichal Meloun DIV7_1(0, "pllREFE_out1_div", "pllREFE", PLLREFE_OUT, 8), 560e9034789SMichal Meloun 561e9034789SMichal Meloun DIV_TB(TEGRA210_CLK_PLL_C4_OUT0, 562e9034789SMichal Meloun "pllC4_out0", "pllC4", PLLC4_BASE, 19, 5, tegra210_pll_pdiv_tbl), 563e9034789SMichal Meloun DIV7_1(0, "pllC4_out3_div", "pllC4_out0", PLLC4_OUT, 8), 564e9034789SMichal Meloun 565e9034789SMichal Meloun DIV7_1(0, "pllA_out0_div", "pllA", PLLA_OUT, 8), 566e9034789SMichal Meloun 567e9034789SMichal Meloun }; 568e9034789SMichal Meloun 569e9034789SMichal Meloun static int tegra210_pll_init(struct clknode *clk, device_t dev); 570e9034789SMichal Meloun static int tegra210_pll_set_gate(struct clknode *clk, bool enable); 571*7c0ec663SMichal Meloun static int tegra210_pll_get_gate(struct clknode *clk, bool *enabled); 572e9034789SMichal Meloun static int tegra210_pll_recalc(struct clknode *clk, uint64_t *freq); 573e9034789SMichal Meloun static int tegra210_pll_set_freq(struct clknode *clknode, uint64_t fin, 574e9034789SMichal Meloun uint64_t *fout, int flags, int *stop); 575e9034789SMichal Meloun struct pll_sc { 576e9034789SMichal Meloun device_t clkdev; 577e9034789SMichal Meloun enum pll_type type; 578e9034789SMichal Meloun uint32_t base_reg; 579e9034789SMichal Meloun uint32_t misc_reg; 580e9034789SMichal Meloun uint32_t lock_enable; 581e9034789SMichal Meloun uint32_t iddq_reg; 582e9034789SMichal Meloun uint32_t iddq_mask; 583e9034789SMichal Meloun uint32_t flags; 584e9034789SMichal Meloun struct pdiv_table *pdiv_table; 585e9034789SMichal Meloun struct mnp_bits mnp_bits; 586e9034789SMichal Meloun }; 587e9034789SMichal Meloun 588e9034789SMichal Meloun static clknode_method_t tegra210_pll_methods[] = { 589e9034789SMichal Meloun /* Device interface */ 590e9034789SMichal Meloun CLKNODEMETHOD(clknode_init, tegra210_pll_init), 591e9034789SMichal Meloun CLKNODEMETHOD(clknode_set_gate, tegra210_pll_set_gate), 592*7c0ec663SMichal Meloun CLKNODEMETHOD(clknode_get_gate, tegra210_pll_get_gate), 593e9034789SMichal Meloun CLKNODEMETHOD(clknode_recalc_freq, tegra210_pll_recalc), 594e9034789SMichal Meloun CLKNODEMETHOD(clknode_set_freq, tegra210_pll_set_freq), 595e9034789SMichal Meloun CLKNODEMETHOD_END 596e9034789SMichal Meloun }; 597e9034789SMichal Meloun DEFINE_CLASS_1(tegra210_pll, tegra210_pll_class, tegra210_pll_methods, 598e9034789SMichal Meloun sizeof(struct pll_sc), clknode_class); 599e9034789SMichal Meloun 600e9034789SMichal Meloun static int 601e9034789SMichal Meloun pll_enable(struct pll_sc *sc) 602e9034789SMichal Meloun { 603e9034789SMichal Meloun uint32_t reg; 604e9034789SMichal Meloun 605e9034789SMichal Meloun 606e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 607e9034789SMichal Meloun if (sc->type != PLL_E) 608e9034789SMichal Meloun reg &= ~PLL_BASE_BYPASS; 609e9034789SMichal Meloun reg |= PLL_BASE_ENABLE; 610e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 611e9034789SMichal Meloun return (0); 612e9034789SMichal Meloun } 613e9034789SMichal Meloun 614e9034789SMichal Meloun static int 615e9034789SMichal Meloun pll_disable(struct pll_sc *sc) 616e9034789SMichal Meloun { 617e9034789SMichal Meloun uint32_t reg; 618e9034789SMichal Meloun 619e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 620e9034789SMichal Meloun if (sc->type != PLL_E) 621e9034789SMichal Meloun reg |= PLL_BASE_BYPASS; 622e9034789SMichal Meloun reg &= ~PLL_BASE_ENABLE; 623e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 624e9034789SMichal Meloun return (0); 625e9034789SMichal Meloun } 626e9034789SMichal Meloun 627e9034789SMichal Meloun static uint32_t 628e9034789SMichal Meloun pdiv_to_reg(struct pll_sc *sc, uint32_t p_div) 629e9034789SMichal Meloun { 630e9034789SMichal Meloun struct pdiv_table *tbl; 631e9034789SMichal Meloun 632e9034789SMichal Meloun tbl = sc->pdiv_table; 633e9034789SMichal Meloun if (tbl == NULL) { 634e9034789SMichal Meloun if (sc->flags & PLL_FLAG_PDIV_POWER2) 635e9034789SMichal Meloun return (ffs(p_div) - 1); 636e9034789SMichal Meloun else 637e9034789SMichal Meloun return (p_div); 638e9034789SMichal Meloun } 639e9034789SMichal Meloun 640e9034789SMichal Meloun while (tbl->divider != 0) { 641e9034789SMichal Meloun if (p_div <= tbl->divider) 642e9034789SMichal Meloun return (tbl->value); 643e9034789SMichal Meloun tbl++; 644e9034789SMichal Meloun } 645e9034789SMichal Meloun return (0xFFFFFFFF); 646e9034789SMichal Meloun } 647e9034789SMichal Meloun 648e9034789SMichal Meloun static uint32_t 649e9034789SMichal Meloun reg_to_pdiv(struct pll_sc *sc, uint32_t reg) 650e9034789SMichal Meloun { 651e9034789SMichal Meloun struct pdiv_table *tbl; 652e9034789SMichal Meloun 653e9034789SMichal Meloun tbl = sc->pdiv_table; 654e9034789SMichal Meloun if (tbl == NULL) { 655e9034789SMichal Meloun if (sc->flags & PLL_FLAG_PDIV_POWER2) 656e9034789SMichal Meloun return (1 << reg); 657e9034789SMichal Meloun else 658e9034789SMichal Meloun return (reg == 0 ? 1: reg); 659e9034789SMichal Meloun } 660e9034789SMichal Meloun while (tbl->divider) { 661e9034789SMichal Meloun if (reg == tbl->value) 662e9034789SMichal Meloun return (tbl->divider); 663e9034789SMichal Meloun tbl++; 664e9034789SMichal Meloun } 665e9034789SMichal Meloun return (0); 666e9034789SMichal Meloun } 667e9034789SMichal Meloun 668e9034789SMichal Meloun static uint32_t 669e9034789SMichal Meloun get_masked(uint32_t val, uint32_t shift, uint32_t width) 670e9034789SMichal Meloun { 671e9034789SMichal Meloun 672e9034789SMichal Meloun return ((val >> shift) & ((1 << width) - 1)); 673e9034789SMichal Meloun } 674e9034789SMichal Meloun 675e9034789SMichal Meloun static uint32_t 676e9034789SMichal Meloun set_masked(uint32_t val, uint32_t v, uint32_t shift, uint32_t width) 677e9034789SMichal Meloun { 678e9034789SMichal Meloun 679e9034789SMichal Meloun val &= ~(((1 << width) - 1) << shift); 680e9034789SMichal Meloun val |= (v & ((1 << width) - 1)) << shift; 681e9034789SMichal Meloun return (val); 682e9034789SMichal Meloun } 683e9034789SMichal Meloun 684e9034789SMichal Meloun static void 685e9034789SMichal Meloun get_divisors(struct pll_sc *sc, uint32_t *m, uint32_t *n, uint32_t *p) 686e9034789SMichal Meloun { 687e9034789SMichal Meloun uint32_t val; 688e9034789SMichal Meloun struct mnp_bits *mnp_bits; 689e9034789SMichal Meloun 690e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 691e9034789SMichal Meloun RD4(sc, sc->base_reg, &val); 692e9034789SMichal Meloun *m = get_masked(val, mnp_bits->m_shift, mnp_bits->m_width); 693e9034789SMichal Meloun *n = get_masked(val, mnp_bits->n_shift, mnp_bits->n_width); 694e9034789SMichal Meloun *p = get_masked(val, mnp_bits->p_shift, mnp_bits->p_width); 695e9034789SMichal Meloun } 696e9034789SMichal Meloun 697e9034789SMichal Meloun static uint32_t 698e9034789SMichal Meloun set_divisors(struct pll_sc *sc, uint32_t val, uint32_t m, uint32_t n, 699e9034789SMichal Meloun uint32_t p) 700e9034789SMichal Meloun { 701e9034789SMichal Meloun struct mnp_bits *mnp_bits; 702e9034789SMichal Meloun 703e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 704e9034789SMichal Meloun val = set_masked(val, m, mnp_bits->m_shift, mnp_bits->m_width); 705e9034789SMichal Meloun val = set_masked(val, n, mnp_bits->n_shift, mnp_bits->n_width); 706e9034789SMichal Meloun val = set_masked(val, p, mnp_bits->p_shift, mnp_bits->p_width); 707e9034789SMichal Meloun return (val); 708e9034789SMichal Meloun } 709e9034789SMichal Meloun 710e9034789SMichal Meloun static bool 711e9034789SMichal Meloun is_locked(struct pll_sc *sc) 712e9034789SMichal Meloun { 713e9034789SMichal Meloun uint32_t reg; 714e9034789SMichal Meloun 715e9034789SMichal Meloun switch (sc->type) { 716e9034789SMichal Meloun case PLL_REFE: 717e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 718e9034789SMichal Meloun reg &= PLLREFE_MISC_LOCK; 719e9034789SMichal Meloun break; 720e9034789SMichal Meloun 721e9034789SMichal Meloun case PLL_E: 722e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 723e9034789SMichal Meloun reg &= PLLE_MISC_LOCK; 724e9034789SMichal Meloun break; 725e9034789SMichal Meloun 726e9034789SMichal Meloun default: 727e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 728e9034789SMichal Meloun reg &= PLL_BASE_LOCK; 729e9034789SMichal Meloun break; 730e9034789SMichal Meloun } 731e9034789SMichal Meloun return (reg != 0); 732e9034789SMichal Meloun } 733e9034789SMichal Meloun 734e9034789SMichal Meloun static int 735e9034789SMichal Meloun wait_for_lock(struct pll_sc *sc) 736e9034789SMichal Meloun { 737e9034789SMichal Meloun int i; 738e9034789SMichal Meloun 739e9034789SMichal Meloun for (i = PLL_LOCK_TIMEOUT / 10; i > 0; i--) { 740e9034789SMichal Meloun if (is_locked(sc)) 741e9034789SMichal Meloun break; 742e9034789SMichal Meloun DELAY(10); 743e9034789SMichal Meloun } 744e9034789SMichal Meloun if (i <= 0) { 745e9034789SMichal Meloun printf("PLL lock timeout\n"); 746e9034789SMichal Meloun return (ETIMEDOUT); 747e9034789SMichal Meloun } 748e9034789SMichal Meloun return (0); 749e9034789SMichal Meloun } 750e9034789SMichal Meloun 751e9034789SMichal Meloun static int 752e9034789SMichal Meloun plle_enable(struct pll_sc *sc) 753e9034789SMichal Meloun { 754e9034789SMichal Meloun uint32_t reg; 755e9034789SMichal Meloun int rv; 756e9034789SMichal Meloun struct mnp_bits *mnp_bits; 757e9034789SMichal Meloun uint32_t pll_m = 2; 758e9034789SMichal Meloun uint32_t pll_n = 125; 759e9034789SMichal Meloun uint32_t pll_cml = 14; 760e9034789SMichal Meloun 761e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 762e9034789SMichal Meloun 763e9034789SMichal Meloun /* Disable lock override. */ 764e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 765e9034789SMichal Meloun reg &= ~PLLE_BASE_LOCK_OVERRIDE; 766e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 767e9034789SMichal Meloun 768e9034789SMichal Meloun /* Enable SW control */ 769e9034789SMichal Meloun RD4(sc, PLLE_AUX, ®); 770e9034789SMichal Meloun reg |= PLLE_AUX_ENABLE_SWCTL; 771e9034789SMichal Meloun reg &= ~PLLE_AUX_SEQ_ENABLE; 772e9034789SMichal Meloun WR4(sc, PLLE_AUX, reg); 773e9034789SMichal Meloun DELAY(10); 774e9034789SMichal Meloun 775e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 776e9034789SMichal Meloun reg |= PLLE_MISC_LOCK_ENABLE; 777e9034789SMichal Meloun reg |= PLLE_MISC_IDDQ_SWCTL; 778e9034789SMichal Meloun reg &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE; 779e9034789SMichal Meloun reg |= PLLE_MISC_PTS; 780e9034789SMichal Meloun reg &= ~PLLE_MISC_VREG_BG_CTRL(~0); 781e9034789SMichal Meloun reg &= ~PLLE_MISC_VREG_CTRL(~0); 782e9034789SMichal Meloun WR4(sc, sc->misc_reg, reg); 783e9034789SMichal Meloun DELAY(10); 784e9034789SMichal Meloun 785e9034789SMichal Meloun RD4(sc, PLLE_SS_CNTL, ®); 786e9034789SMichal Meloun reg |= PLLE_SS_CNTL_DISABLE; 787e9034789SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 788e9034789SMichal Meloun 789e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 790e9034789SMichal Meloun reg = set_divisors(sc, reg, pll_m, pll_n, pll_cml); 791e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 792e9034789SMichal Meloun DELAY(10); 793e9034789SMichal Meloun 794e9034789SMichal Meloun pll_enable(sc); 795e9034789SMichal Meloun rv = wait_for_lock(sc); 796e9034789SMichal Meloun if (rv != 0) 797e9034789SMichal Meloun return (rv); 798e9034789SMichal Meloun 799e9034789SMichal Meloun RD4(sc, PLLE_SS_CNTL, ®); 800e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCINCINTRV(~0); 801e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCINC(~0); 802e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCINVERT; 803e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCCENTER; 804e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCMAX(~0); 805e9034789SMichal Meloun reg |= PLLE_SS_CNTL_SSCINCINTRV(0x23); 806e9034789SMichal Meloun reg |= PLLE_SS_CNTL_SSCINC(0x1); 807e9034789SMichal Meloun reg |= PLLE_SS_CNTL_SSCMAX(0x21); 808e9034789SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 809e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_SSCBYP; 810e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_BYPASS_SS; 811e9034789SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 812e9034789SMichal Meloun DELAY(10); 813e9034789SMichal Meloun 814e9034789SMichal Meloun reg &= ~PLLE_SS_CNTL_INTERP_RESET; 815e9034789SMichal Meloun WR4(sc, PLLE_SS_CNTL, reg); 816e9034789SMichal Meloun DELAY(10); 817e9034789SMichal Meloun 818e9034789SMichal Meloun /* HW control of brick pll. */ 819e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 820e9034789SMichal Meloun reg &= ~PLLE_MISC_IDDQ_SWCTL; 821e9034789SMichal Meloun WR4(sc, sc->misc_reg, reg); 822e9034789SMichal Meloun 823e9034789SMichal Meloun RD4(sc, PLLE_AUX, ®); 824e9034789SMichal Meloun reg |= PLLE_AUX_USE_LOCKDET; 825e9034789SMichal Meloun reg |= PLLE_AUX_SS_SEQ_INCLUDE; 826e9034789SMichal Meloun reg &= ~PLLE_AUX_ENABLE_SWCTL; 827e9034789SMichal Meloun reg &= ~PLLE_AUX_SS_SWCTL; 828e9034789SMichal Meloun WR4(sc, PLLE_AUX, reg); 829e9034789SMichal Meloun reg |= PLLE_AUX_SEQ_START_STATE; 830e9034789SMichal Meloun DELAY(10); 831e9034789SMichal Meloun reg |= PLLE_AUX_SEQ_ENABLE; 832e9034789SMichal Meloun WR4(sc, PLLE_AUX, reg); 833e9034789SMichal Meloun 834e9034789SMichal Meloun /* Enable and start XUSBIO PLL HW control*/ 835e9034789SMichal Meloun RD4(sc, XUSBIO_PLL_CFG0, ®); 836e9034789SMichal Meloun reg &= ~XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL; 837e9034789SMichal Meloun reg &= ~XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL; 838e9034789SMichal Meloun reg |= XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET; 839e9034789SMichal Meloun reg |= XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ; 840e9034789SMichal Meloun reg &= ~XUSBIO_PLL_CFG0_SEQ_ENABLE; 841e9034789SMichal Meloun WR4(sc, XUSBIO_PLL_CFG0, reg); 842e9034789SMichal Meloun DELAY(10); 843e9034789SMichal Meloun 844e9034789SMichal Meloun reg |= XUSBIO_PLL_CFG0_SEQ_ENABLE; 845e9034789SMichal Meloun WR4(sc, XUSBIO_PLL_CFG0, reg); 846e9034789SMichal Meloun 847e9034789SMichal Meloun 848e9034789SMichal Meloun /* Enable and start SATA PLL HW control */ 849e9034789SMichal Meloun RD4(sc, SATA_PLL_CFG0, ®); 850e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_PADPLL_RESET_SWCTL; 851e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_PADPLL_RESET_OVERRIDE_VALUE; 852e9034789SMichal Meloun reg |= SATA_PLL_CFG0_PADPLL_USE_LOCKDET; 853e9034789SMichal Meloun reg |= SATA_PLL_CFG0_PADPLL_SLEEP_IDDQ; 854e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_IN_SWCTL; 855e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_RESET_INPUT_VALUE; 856e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_LANE_PD_INPUT_VALUE; 857e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_PADPLL_PD_INPUT_VALUE; 858e9034789SMichal Meloun reg &= ~SATA_PLL_CFG0_SEQ_ENABLE; 859e9034789SMichal Meloun WR4(sc, SATA_PLL_CFG0, reg); 860e9034789SMichal Meloun DELAY(10); 861e9034789SMichal Meloun reg |= SATA_PLL_CFG0_SEQ_ENABLE; 862e9034789SMichal Meloun WR4(sc, SATA_PLL_CFG0, reg); 863e9034789SMichal Meloun 864e9034789SMichal Meloun /* Enable HW control of PCIe PLL. */ 865e9034789SMichal Meloun RD4(sc, PCIE_PLL_CFG, ®); 866e9034789SMichal Meloun reg |= PCIE_PLL_CFG_SEQ_ENABLE; 867e9034789SMichal Meloun WR4(sc, PCIE_PLL_CFG, reg); 868e9034789SMichal Meloun 869e9034789SMichal Meloun return (0); 870e9034789SMichal Meloun } 871e9034789SMichal Meloun 872e9034789SMichal Meloun static int 873e9034789SMichal Meloun tegra210_pll_set_gate(struct clknode *clknode, bool enable) 874e9034789SMichal Meloun { 875e9034789SMichal Meloun int rv; 876e9034789SMichal Meloun struct pll_sc *sc; 877e9034789SMichal Meloun 878e9034789SMichal Meloun sc = clknode_get_softc(clknode); 879e9034789SMichal Meloun if (enable == 0) { 880e9034789SMichal Meloun rv = pll_disable(sc); 881e9034789SMichal Meloun return(rv); 882e9034789SMichal Meloun } 883e9034789SMichal Meloun 884e9034789SMichal Meloun if (sc->type == PLL_E) 885e9034789SMichal Meloun rv = plle_enable(sc); 886e9034789SMichal Meloun else 887e9034789SMichal Meloun rv = pll_enable(sc); 888e9034789SMichal Meloun return (rv); 889e9034789SMichal Meloun } 890e9034789SMichal Meloun 891e9034789SMichal Meloun static int 892*7c0ec663SMichal Meloun tegra210_pll_get_gate(struct clknode *clknode, bool *enabled) 893*7c0ec663SMichal Meloun { 894*7c0ec663SMichal Meloun uint32_t reg; 895*7c0ec663SMichal Meloun struct pll_sc *sc; 896*7c0ec663SMichal Meloun 897*7c0ec663SMichal Meloun sc = clknode_get_softc(clknode); 898*7c0ec663SMichal Meloun RD4(sc, sc->base_reg, ®); 899*7c0ec663SMichal Meloun *enabled = reg & PLL_BASE_ENABLE ? true: false; 900*7c0ec663SMichal Meloun WR4(sc, sc->base_reg, reg); 901*7c0ec663SMichal Meloun return (0); 902*7c0ec663SMichal Meloun } 903*7c0ec663SMichal Meloun 904*7c0ec663SMichal Meloun static int 905e9034789SMichal Meloun pll_set_std(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags, 906e9034789SMichal Meloun uint32_t m, uint32_t n, uint32_t p) 907e9034789SMichal Meloun { 908e9034789SMichal Meloun uint32_t reg; 909e9034789SMichal Meloun struct mnp_bits *mnp_bits; 910e9034789SMichal Meloun int rv; 911e9034789SMichal Meloun 912e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 913e9034789SMichal Meloun if (m >= (1 << mnp_bits->m_width)) 914e9034789SMichal Meloun return (ERANGE); 915e9034789SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 916e9034789SMichal Meloun return (ERANGE); 917e9034789SMichal Meloun if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width)) 918e9034789SMichal Meloun return (ERANGE); 919e9034789SMichal Meloun 920e9034789SMichal Meloun if (flags & CLK_SET_DRYRUN) { 921e9034789SMichal Meloun if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && 922e9034789SMichal Meloun (*fout != (((fin / m) * n) /p))) 923e9034789SMichal Meloun return (ERANGE); 924e9034789SMichal Meloun 925e9034789SMichal Meloun *fout = ((fin / m) * n) /p; 926e9034789SMichal Meloun 927e9034789SMichal Meloun return (0); 928e9034789SMichal Meloun } 929e9034789SMichal Meloun 930e9034789SMichal Meloun pll_disable(sc); 931e9034789SMichal Meloun 932e9034789SMichal Meloun /* take pll out of IDDQ */ 933e9034789SMichal Meloun if (sc->iddq_reg != 0) 934e9034789SMichal Meloun MD4(sc, sc->iddq_reg, sc->iddq_mask, 0); 935e9034789SMichal Meloun 936e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 937e9034789SMichal Meloun reg = set_masked(reg, m, mnp_bits->m_shift, mnp_bits->m_width); 938e9034789SMichal Meloun reg = set_masked(reg, n, mnp_bits->n_shift, mnp_bits->n_width); 939e9034789SMichal Meloun reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift, 940e9034789SMichal Meloun mnp_bits->p_width); 941e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 942e9034789SMichal Meloun 943e9034789SMichal Meloun /* Enable PLL. */ 944e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 945e9034789SMichal Meloun reg |= PLL_BASE_ENABLE; 946e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 947e9034789SMichal Meloun 948e9034789SMichal Meloun /* Enable lock detection. */ 949e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 950e9034789SMichal Meloun reg |= sc->lock_enable; 951e9034789SMichal Meloun WR4(sc, sc->misc_reg, reg); 952e9034789SMichal Meloun 953e9034789SMichal Meloun rv = wait_for_lock(sc); 954e9034789SMichal Meloun if (rv != 0) { 955e9034789SMichal Meloun /* Disable PLL */ 956e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 957e9034789SMichal Meloun reg &= ~PLL_BASE_ENABLE; 958e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 959e9034789SMichal Meloun return (rv); 960e9034789SMichal Meloun } 961e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 962e9034789SMichal Meloun 963e9034789SMichal Meloun pll_enable(sc); 964e9034789SMichal Meloun *fout = ((fin / m) * n) / p; 965e9034789SMichal Meloun return 0; 966e9034789SMichal Meloun } 967e9034789SMichal Meloun 968e9034789SMichal Meloun static int 969e9034789SMichal Meloun plla_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 970e9034789SMichal Meloun { 971e9034789SMichal Meloun uint32_t m, n, p; 972e9034789SMichal Meloun 973e9034789SMichal Meloun p = 1; 974e9034789SMichal Meloun m = 3; 975e9034789SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 976e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 977e9034789SMichal Meloun return (pll_set_std(sc, fin, fout, flags, m, n, p)); 978e9034789SMichal Meloun } 979e9034789SMichal Meloun 980e9034789SMichal Meloun static int 981e9034789SMichal Meloun pllc_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 982e9034789SMichal Meloun { 983e9034789SMichal Meloun uint32_t m, n, p; 984e9034789SMichal Meloun 985e9034789SMichal Meloun p = 2; 986e9034789SMichal Meloun m = 3; 987e9034789SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 988e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 989e9034789SMichal Meloun return (pll_set_std( sc, fin, fout, flags, m, n, p)); 990e9034789SMichal Meloun } 991e9034789SMichal Meloun 992e9034789SMichal Meloun static int 993e9034789SMichal Meloun pllc4_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 994e9034789SMichal Meloun { 995e9034789SMichal Meloun uint32_t m, n, p; 996e9034789SMichal Meloun 997e9034789SMichal Meloun p = 1; 998e9034789SMichal Meloun m = 4; 999e9034789SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 1000e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 1001e9034789SMichal Meloun return (pll_set_std( sc, fin, fout, flags, m, n, p)); 1002e9034789SMichal Meloun } 1003e9034789SMichal Meloun 1004e9034789SMichal Meloun static int 1005e9034789SMichal Meloun plldp_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 1006e9034789SMichal Meloun { 1007e9034789SMichal Meloun uint32_t m, n, p; 1008e9034789SMichal Meloun 1009e9034789SMichal Meloun p = 1; 1010e9034789SMichal Meloun m = 4; 1011e9034789SMichal Meloun n = (*fout * p * m + fin / 2)/ fin; 1012e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 1013e9034789SMichal Meloun return (pll_set_std( sc, fin, fout, flags, m, n, p)); 1014e9034789SMichal Meloun } 1015e9034789SMichal Meloun 1016e9034789SMichal Meloun 1017e9034789SMichal Meloun /* 1018e9034789SMichal Meloun * PLLD2 is used as source for pixel clock for HDMI. 1019e9034789SMichal Meloun * We must be able to set it frequency very flexibly and 1020e9034789SMichal Meloun * precisely (within 5% tolerance limit allowed by HDMI specs). 1021e9034789SMichal Meloun * 1022e9034789SMichal Meloun * For this reason, it is necessary to search the full state space. 1023e9034789SMichal Meloun * Fortunately, thanks to early cycle terminations, performance 1024e9034789SMichal Meloun * is within acceptable limits. 1025e9034789SMichal Meloun */ 1026e9034789SMichal Meloun #define PLLD2_PFD_MIN 12000000 /* 12 MHz */ 1027e9034789SMichal Meloun #define PLLD2_PFD_MAX 38400000 /* 38.4 MHz */ 1028e9034789SMichal Meloun #define PLLD2_VCO_MIN 750000000 /* 750 MHz */ 1029e9034789SMichal Meloun #define PLLD2_VCO_MAX 1500000000 /* 1.5 GHz */ 1030e9034789SMichal Meloun 1031e9034789SMichal Meloun static int 1032e9034789SMichal Meloun plld2_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 1033e9034789SMichal Meloun { 1034e9034789SMichal Meloun uint32_t m, n, p; 1035e9034789SMichal Meloun uint32_t best_m, best_n, best_p; 1036e9034789SMichal Meloun uint64_t vco, pfd; 1037e9034789SMichal Meloun int64_t err, best_err; 1038e9034789SMichal Meloun struct mnp_bits *mnp_bits; 1039e9034789SMichal Meloun struct pdiv_table *tbl; 1040e9034789SMichal Meloun int p_idx, rv; 1041e9034789SMichal Meloun 1042e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 1043e9034789SMichal Meloun tbl = sc->pdiv_table; 1044e9034789SMichal Meloun best_err = INT64_MAX; 1045e9034789SMichal Meloun 1046e9034789SMichal Meloun for (p_idx = 0; tbl[p_idx].divider != 0; p_idx++) { 1047e9034789SMichal Meloun p = tbl[p_idx].divider; 1048e9034789SMichal Meloun 1049e9034789SMichal Meloun /* Check constraints */ 1050e9034789SMichal Meloun vco = *fout * p; 1051e9034789SMichal Meloun if (vco < PLLD2_VCO_MIN) 1052e9034789SMichal Meloun continue; 1053e9034789SMichal Meloun if (vco > PLLD2_VCO_MAX) 1054e9034789SMichal Meloun break; 1055e9034789SMichal Meloun 1056e9034789SMichal Meloun for (m = 1; m < (1 << mnp_bits->m_width); m++) { 1057e9034789SMichal Meloun n = (*fout * p * m + fin / 2) / fin; 1058e9034789SMichal Meloun 1059e9034789SMichal Meloun /* Check constraints */ 1060e9034789SMichal Meloun if (n == 0) 1061e9034789SMichal Meloun continue; 1062e9034789SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 1063e9034789SMichal Meloun break; 1064e9034789SMichal Meloun vco = (fin * n) / m; 1065e9034789SMichal Meloun if (vco > PLLD2_VCO_MAX || vco < PLLD2_VCO_MIN) 1066e9034789SMichal Meloun continue; 1067e9034789SMichal Meloun pfd = fin / m; 1068e9034789SMichal Meloun if (pfd > PLLD2_PFD_MAX || vco < PLLD2_PFD_MIN) 1069e9034789SMichal Meloun continue; 1070e9034789SMichal Meloun 1071e9034789SMichal Meloun /* Constraints passed, save best result */ 1072e9034789SMichal Meloun err = *fout - vco / p; 1073e9034789SMichal Meloun if (err < 0) 1074e9034789SMichal Meloun err = -err; 1075e9034789SMichal Meloun if (err < best_err) { 1076e9034789SMichal Meloun best_err = err; 1077e9034789SMichal Meloun best_p = p; 1078e9034789SMichal Meloun best_m = m; 1079e9034789SMichal Meloun best_n = n; 1080e9034789SMichal Meloun } 1081e9034789SMichal Meloun if (err == 0) 1082e9034789SMichal Meloun goto done; 1083e9034789SMichal Meloun } 1084e9034789SMichal Meloun } 1085e9034789SMichal Meloun done: 1086e9034789SMichal Meloun /* 1087e9034789SMichal Meloun * HDMI specification allows 5% pixel clock tolerance, 1088e9034789SMichal Meloun * we will by a slightly stricter 1089e9034789SMichal Meloun */ 1090e9034789SMichal Meloun if (best_err > ((*fout * 100) / 4)) 1091e9034789SMichal Meloun return (ERANGE); 1092e9034789SMichal Meloun 1093e9034789SMichal Meloun if (flags & CLK_SET_DRYRUN) 1094e9034789SMichal Meloun return (0); 1095e9034789SMichal Meloun rv = pll_set_std(sc, fin, fout, flags, best_m, best_n, best_p); 1096e9034789SMichal Meloun /* XXXX Panic for rv == ERANGE ? */ 1097e9034789SMichal Meloun return (rv); 1098e9034789SMichal Meloun } 1099e9034789SMichal Meloun 1100e9034789SMichal Meloun static int 1101e9034789SMichal Meloun pllrefe_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 1102e9034789SMichal Meloun { 1103e9034789SMichal Meloun uint32_t m, n, p; 1104e9034789SMichal Meloun 1105e9034789SMichal Meloun m = 1; 1106e9034789SMichal Meloun p = 1; 1107e9034789SMichal Meloun n = *fout * p * m / fin; 1108e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 1109e9034789SMichal Meloun return (pll_set_std(sc, fin, fout, flags, m, n, p)); 1110e9034789SMichal Meloun } 1111e9034789SMichal Meloun 1112e9034789SMichal Meloun #define PLLX_PFD_MIN 12000000LL /* 12 MHz */ 1113e9034789SMichal Meloun #define PLLX_PFD_MAX 38400000LL /* 38.4 MHz */ 1114e9034789SMichal Meloun #define PLLX_VCO_MIN 900000000LL /* 0.9 GHz */ 1115e9034789SMichal Meloun #define PLLX_VCO_MAX 3000000000LL /* 3 GHz */ 1116e9034789SMichal Meloun 1117e9034789SMichal Meloun static int 1118e9034789SMichal Meloun pllx_set_freq(struct pll_sc *sc, uint64_t fin, uint64_t *fout, int flags) 1119e9034789SMichal Meloun { 1120e9034789SMichal Meloun struct mnp_bits *mnp_bits; 1121e9034789SMichal Meloun uint32_t m, n, p; 1122e9034789SMichal Meloun uint32_t old_m, old_n, old_p; 1123e9034789SMichal Meloun uint32_t reg; 1124e9034789SMichal Meloun int i, rv; 1125e9034789SMichal Meloun 1126e9034789SMichal Meloun mnp_bits = &sc->mnp_bits; 1127e9034789SMichal Meloun 1128e9034789SMichal Meloun get_divisors(sc, &old_m, &old_n, &old_p); 1129e9034789SMichal Meloun old_p = reg_to_pdiv(sc, old_p); 1130e9034789SMichal Meloun 1131e9034789SMichal Meloun /* Pre-divider is fixed, Compute post-divider */ 1132e9034789SMichal Meloun m = old_m; 1133e9034789SMichal Meloun p = 1; 1134e9034789SMichal Meloun while ((*fout * p) < PLLX_VCO_MIN) 1135e9034789SMichal Meloun p++; 1136e9034789SMichal Meloun if ((*fout * p) > PLLX_VCO_MAX) 1137e9034789SMichal Meloun return (ERANGE); 1138e9034789SMichal Meloun 1139e9034789SMichal Meloun n = (*fout * p * m + fin / 2) / fin; 1140e9034789SMichal Meloun dprintf("%s: m: %d, n: %d, p: %d\n", __func__, m, n, p); 1141e9034789SMichal Meloun 1142e9034789SMichal Meloun if (m >= (1 << mnp_bits->m_width)) 1143e9034789SMichal Meloun return (ERANGE); 1144e9034789SMichal Meloun if (n >= (1 << mnp_bits->n_width)) 1145e9034789SMichal Meloun return (ERANGE); 1146e9034789SMichal Meloun if (pdiv_to_reg(sc, p) >= (1 << mnp_bits->p_width)) 1147e9034789SMichal Meloun return (ERANGE); 1148e9034789SMichal Meloun 1149e9034789SMichal Meloun if (flags & CLK_SET_DRYRUN) { 1150e9034789SMichal Meloun if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && 1151e9034789SMichal Meloun (*fout != (((fin / m) * n) /p))) 1152e9034789SMichal Meloun return (ERANGE); 1153e9034789SMichal Meloun *fout = ((fin / m) * n) /p; 1154e9034789SMichal Meloun return (0); 1155e9034789SMichal Meloun } 1156e9034789SMichal Meloun 1157e9034789SMichal Meloun /* If new post-divider is bigger that original, set it now. */ 1158e9034789SMichal Meloun if (p < old_p) { 1159e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 1160e9034789SMichal Meloun reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift, 1161e9034789SMichal Meloun mnp_bits->p_width); 1162e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 1163e9034789SMichal Meloun } 1164e9034789SMichal Meloun DELAY(100); 1165e9034789SMichal Meloun 1166e9034789SMichal Meloun /* vvv Program dynamic VCO ramp. vvv */ 1167e9034789SMichal Meloun /* 1 - disable dynamic ramp mode. */ 1168e9034789SMichal Meloun RD4(sc, PLLX_MISC_2, ®); 1169e9034789SMichal Meloun reg &= ~PLLX_MISC_2_EN_DYNRAMP; 1170e9034789SMichal Meloun WR4(sc, PLLX_MISC_2, reg); 1171e9034789SMichal Meloun 1172e9034789SMichal Meloun /* 2 - Setup new ndiv. */ 1173e9034789SMichal Meloun RD4(sc, PLLX_MISC_2, ®); 1174e9034789SMichal Meloun reg &= ~PLLX_MISC_2_NDIV_NEW(~0); 1175e9034789SMichal Meloun reg |= PLLX_MISC_2_NDIV_NEW(n); 1176e9034789SMichal Meloun WR4(sc, PLLX_MISC_2, reg); 1177e9034789SMichal Meloun 1178e9034789SMichal Meloun /* 3 - enable dynamic ramp. */ 1179e9034789SMichal Meloun RD4(sc, PLLX_MISC_2, ®); 1180e9034789SMichal Meloun reg |= PLLX_MISC_2_EN_DYNRAMP; 1181e9034789SMichal Meloun WR4(sc, PLLX_MISC_2, reg); 1182e9034789SMichal Meloun 1183e9034789SMichal Meloun /* 4 - wait for done. */ 1184e9034789SMichal Meloun for (i = PLL_LOCK_TIMEOUT / 10; i > 0; i--) { 1185e9034789SMichal Meloun RD4(sc, PLLX_MISC_2, ®); 1186e9034789SMichal Meloun if (reg & PLLX_MISC_2_DYNRAMP_DONE) 1187e9034789SMichal Meloun break; 1188e9034789SMichal Meloun DELAY(10); 1189e9034789SMichal Meloun } 1190e9034789SMichal Meloun if (i <= 0) { 1191e9034789SMichal Meloun printf("PLL X dynamic ramp timedout\n"); 1192e9034789SMichal Meloun return (ETIMEDOUT); 1193e9034789SMichal Meloun } 1194e9034789SMichal Meloun 1195e9034789SMichal Meloun /* 5 - copy new ndiv to base register. */ 1196e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 1197e9034789SMichal Meloun reg = set_masked(reg, n, mnp_bits->n_shift, 1198e9034789SMichal Meloun mnp_bits->n_width); 1199e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 1200e9034789SMichal Meloun 1201e9034789SMichal Meloun /* 6 - disable dynamic ramp mode. */ 1202e9034789SMichal Meloun RD4(sc, PLLX_MISC_2, ®); 1203e9034789SMichal Meloun reg &= ~PLLX_MISC_2_EN_DYNRAMP; 1204e9034789SMichal Meloun WR4(sc, PLLX_MISC_2, reg); 1205e9034789SMichal Meloun 1206e9034789SMichal Meloun rv = wait_for_lock(sc); 1207e9034789SMichal Meloun if (rv != 0) { 1208e9034789SMichal Meloun printf("PLL X is not locked !!\n"); 1209e9034789SMichal Meloun } 1210e9034789SMichal Meloun /* ^^^ Dynamic ramp done. ^^^ */ 1211e9034789SMichal Meloun 1212e9034789SMichal Meloun /* If new post-divider is smaller that original, set it. */ 1213e9034789SMichal Meloun if (p > old_p) { 1214e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 1215e9034789SMichal Meloun reg = set_masked(reg, pdiv_to_reg(sc, p), mnp_bits->p_shift, 1216e9034789SMichal Meloun mnp_bits->p_width); 1217e9034789SMichal Meloun WR4(sc, sc->base_reg, reg); 1218e9034789SMichal Meloun } 1219e9034789SMichal Meloun 1220e9034789SMichal Meloun *fout = ((fin / m) * n) / p; 1221e9034789SMichal Meloun return (0); 1222e9034789SMichal Meloun } 1223e9034789SMichal Meloun 1224e9034789SMichal Meloun /* Simplified setup for 38.4 MHz clock. */ 1225e9034789SMichal Meloun #define PLLX_STEP_A 0x04 1226e9034789SMichal Meloun #define PLLX_STEP_B 0x05 1227e9034789SMichal Meloun static int 1228e9034789SMichal Meloun pllx_init(struct pll_sc *sc) 1229e9034789SMichal Meloun { 1230e9034789SMichal Meloun uint32_t reg; 1231e9034789SMichal Meloun 1232e9034789SMichal Meloun RD4(sc, PLLX_MISC, ®); 1233e9034789SMichal Meloun reg = PLLX_MISC_LOCK_ENABLE; 1234e9034789SMichal Meloun WR4(sc, PLLX_MISC, reg); 1235e9034789SMichal Meloun 1236e9034789SMichal Meloun /* Setup dynamic ramp. */ 1237e9034789SMichal Meloun reg = 0; 1238e9034789SMichal Meloun reg |= PLLX_MISC_2_DYNRAMP_STEPA(PLLX_STEP_A); 1239e9034789SMichal Meloun reg |= PLLX_MISC_2_DYNRAMP_STEPB(PLLX_STEP_B); 1240e9034789SMichal Meloun WR4(sc, PLLX_MISC_2, reg); 1241e9034789SMichal Meloun 1242e9034789SMichal Meloun /* Disable SDM. */ 1243e9034789SMichal Meloun reg = 0; 1244e9034789SMichal Meloun WR4(sc, PLLX_MISC_4, reg); 1245e9034789SMichal Meloun WR4(sc, PLLX_MISC_5, reg); 1246e9034789SMichal Meloun 1247e9034789SMichal Meloun return (0); 1248e9034789SMichal Meloun } 1249e9034789SMichal Meloun 1250e9034789SMichal Meloun static int 1251e9034789SMichal Meloun tegra210_pll_set_freq(struct clknode *clknode, uint64_t fin, uint64_t *fout, 1252e9034789SMichal Meloun int flags, int *stop) 1253e9034789SMichal Meloun { 1254e9034789SMichal Meloun *stop = 1; 1255e9034789SMichal Meloun int rv; 1256e9034789SMichal Meloun struct pll_sc *sc; 1257e9034789SMichal Meloun 1258e9034789SMichal Meloun sc = clknode_get_softc(clknode); 1259e9034789SMichal Meloun dprintf("%s: %s requested freq: %lu, input freq: %lu\n", __func__, 1260e9034789SMichal Meloun clknode_get_name(clknode), *fout, fin); 1261e9034789SMichal Meloun switch (sc->type) { 1262e9034789SMichal Meloun case PLL_A: 1263e9034789SMichal Meloun rv = plla_set_freq(sc, fin, fout, flags); 1264e9034789SMichal Meloun break; 1265e9034789SMichal Meloun 1266e9034789SMichal Meloun case PLL_C: 1267e9034789SMichal Meloun case PLL_C2: 1268e9034789SMichal Meloun case PLL_C3: 1269e9034789SMichal Meloun rv = pllc_set_freq(sc, fin, fout, flags); 1270e9034789SMichal Meloun break; 1271e9034789SMichal Meloun 1272e9034789SMichal Meloun case PLL_C4: 1273e9034789SMichal Meloun rv = pllc4_set_freq(sc, fin, fout, flags); 1274e9034789SMichal Meloun break; 1275e9034789SMichal Meloun 1276e9034789SMichal Meloun case PLL_D2: 1277e9034789SMichal Meloun rv = plld2_set_freq(sc, fin, fout, flags); 1278e9034789SMichal Meloun break; 1279e9034789SMichal Meloun 1280e9034789SMichal Meloun case PLL_DP: 1281e9034789SMichal Meloun rv = plldp_set_freq(sc, fin, fout, flags); 1282e9034789SMichal Meloun break; 1283e9034789SMichal Meloun 1284e9034789SMichal Meloun case PLL_REFE: 1285e9034789SMichal Meloun rv = pllrefe_set_freq(sc, fin, fout, flags); 1286e9034789SMichal Meloun break; 1287e9034789SMichal Meloun 1288e9034789SMichal Meloun case PLL_X: 1289e9034789SMichal Meloun rv = pllx_set_freq(sc, fin, fout, flags); 1290e9034789SMichal Meloun break; 1291e9034789SMichal Meloun 1292e9034789SMichal Meloun case PLL_U: 1293e9034789SMichal Meloun if (*fout == 480000000) /* PLLU is fixed to 480 MHz */ 1294e9034789SMichal Meloun rv = 0; 1295e9034789SMichal Meloun else 1296e9034789SMichal Meloun rv = ERANGE; 1297e9034789SMichal Meloun break; 1298e9034789SMichal Meloun default: 1299e9034789SMichal Meloun rv = ENXIO; 1300e9034789SMichal Meloun break; 1301e9034789SMichal Meloun } 1302e9034789SMichal Meloun 1303e9034789SMichal Meloun return (rv); 1304e9034789SMichal Meloun } 1305e9034789SMichal Meloun 1306e9034789SMichal Meloun 1307e9034789SMichal Meloun static int 1308e9034789SMichal Meloun tegra210_pll_init(struct clknode *clk, device_t dev) 1309e9034789SMichal Meloun { 1310e9034789SMichal Meloun struct pll_sc *sc; 1311e9034789SMichal Meloun uint32_t reg, rv; 1312e9034789SMichal Meloun 1313e9034789SMichal Meloun sc = clknode_get_softc(clk); 1314e9034789SMichal Meloun 1315e9034789SMichal Meloun if (sc->type == PLL_X) { 1316e9034789SMichal Meloun rv = pllx_init(sc); 1317e9034789SMichal Meloun if (rv != 0) 1318e9034789SMichal Meloun return (rv); 1319e9034789SMichal Meloun } 1320e9034789SMichal Meloun 1321e9034789SMichal Meloun /* If PLL is enabled, enable lock detect too. */ 1322e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 1323e9034789SMichal Meloun if (reg & PLL_BASE_ENABLE) { 1324e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 1325e9034789SMichal Meloun reg |= sc->lock_enable; 1326e9034789SMichal Meloun WR4(sc, sc->misc_reg, reg); 1327e9034789SMichal Meloun } 1328e9034789SMichal Meloun if (sc->type == PLL_REFE) { 1329e9034789SMichal Meloun RD4(sc, sc->misc_reg, ®); 1330e9034789SMichal Meloun reg &= ~(1 << 29); /* Disable lock override */ 1331e9034789SMichal Meloun WR4(sc, sc->misc_reg, reg); 1332e9034789SMichal Meloun } 1333e9034789SMichal Meloun clknode_init_parent_idx(clk, 0); 1334e9034789SMichal Meloun return(0); 1335e9034789SMichal Meloun } 1336e9034789SMichal Meloun 1337e9034789SMichal Meloun static int 1338e9034789SMichal Meloun tegra210_pll_recalc(struct clknode *clk, uint64_t *freq) 1339e9034789SMichal Meloun { 1340e9034789SMichal Meloun struct pll_sc *sc; 1341e9034789SMichal Meloun uint32_t m, n, p, pr; 1342e9034789SMichal Meloun uint32_t reg, misc_reg; 1343e9034789SMichal Meloun int locked; 1344e9034789SMichal Meloun 1345e9034789SMichal Meloun sc = clknode_get_softc(clk); 1346e9034789SMichal Meloun 1347e9034789SMichal Meloun RD4(sc, sc->base_reg, ®); 1348e9034789SMichal Meloun RD4(sc, sc->misc_reg, &misc_reg); 1349e9034789SMichal Meloun 1350e9034789SMichal Meloun get_divisors(sc, &m, &n, &pr); 1351e9034789SMichal Meloun 1352e9034789SMichal Meloun /* If VCO is directlu exposed, P divider is handled by external node */ 1353e9034789SMichal Meloun if (sc->flags & PLL_FLAG_VCO_OUT) 1354e9034789SMichal Meloun p = 1; 1355e9034789SMichal Meloun else 1356e9034789SMichal Meloun p = reg_to_pdiv(sc, pr); 1357e9034789SMichal Meloun 1358e9034789SMichal Meloun locked = is_locked(sc); 1359e9034789SMichal Meloun 1360e9034789SMichal Meloun dprintf("%s: %s (0x%08x, 0x%08x) - m: %d, n: %d, p: %d (%d): " 1361e9034789SMichal Meloun "e: %d, r: %d, o: %d - %s\n", __func__, 1362e9034789SMichal Meloun clknode_get_name(clk), reg, misc_reg, m, n, p, pr, 1363e9034789SMichal Meloun (reg >> 30) & 1, (reg >> 29) & 1, (reg >> 28) & 1, 1364e9034789SMichal Meloun locked ? "locked" : "unlocked"); 1365e9034789SMichal Meloun 1366e9034789SMichal Meloun if ((m == 0) || (n == 0) || (p == 0)) { 1367e9034789SMichal Meloun *freq = 0; 1368e9034789SMichal Meloun return (EINVAL); 1369e9034789SMichal Meloun } 1370e9034789SMichal Meloun if (!locked) { 1371e9034789SMichal Meloun *freq = 0; 1372e9034789SMichal Meloun return (0); 1373e9034789SMichal Meloun } 1374e9034789SMichal Meloun *freq = ((*freq / m) * n) / p; 1375e9034789SMichal Meloun return (0); 1376e9034789SMichal Meloun } 1377e9034789SMichal Meloun 1378e9034789SMichal Meloun static int 1379e9034789SMichal Meloun pll_register(struct clkdom *clkdom, struct clk_pll_def *clkdef) 1380e9034789SMichal Meloun { 1381e9034789SMichal Meloun struct clknode *clk; 1382e9034789SMichal Meloun struct pll_sc *sc; 1383e9034789SMichal Meloun 1384e9034789SMichal Meloun clk = clknode_create(clkdom, &tegra210_pll_class, &clkdef->clkdef); 1385e9034789SMichal Meloun if (clk == NULL) 1386e9034789SMichal Meloun return (ENXIO); 1387e9034789SMichal Meloun 1388e9034789SMichal Meloun sc = clknode_get_softc(clk); 1389e9034789SMichal Meloun sc->clkdev = clknode_get_device(clk); 1390e9034789SMichal Meloun sc->type = clkdef->type; 1391e9034789SMichal Meloun sc->base_reg = clkdef->base_reg; 1392e9034789SMichal Meloun sc->misc_reg = clkdef->misc_reg; 1393e9034789SMichal Meloun sc->lock_enable = clkdef->lock_enable; 1394e9034789SMichal Meloun sc->iddq_reg = clkdef->iddq_reg; 1395e9034789SMichal Meloun sc->iddq_mask = clkdef->iddq_mask; 1396e9034789SMichal Meloun sc->flags = clkdef->flags; 1397e9034789SMichal Meloun sc->pdiv_table = clkdef->pdiv_table; 1398e9034789SMichal Meloun sc->mnp_bits = clkdef->mnp_bits; 1399e9034789SMichal Meloun clknode_register(clkdom, clk); 1400e9034789SMichal Meloun return (0); 1401e9034789SMichal Meloun } 1402e9034789SMichal Meloun 1403e9034789SMichal Meloun static void config_utmi_pll(struct tegra210_car_softc *sc) 1404e9034789SMichal Meloun { 1405e9034789SMichal Meloun uint32_t reg; 1406e9034789SMichal Meloun /* 1407e9034789SMichal Meloun * XXX Simplified UTMIP settings for 38.4MHz base clock. 1408e9034789SMichal Meloun */ 1409e9034789SMichal Meloun #define ENABLE_DELAY_COUNT 0x00 1410e9034789SMichal Meloun #define STABLE_COUNT 0x00 1411e9034789SMichal Meloun #define ACTIVE_DELAY_COUNT 0x06 1412e9034789SMichal Meloun #define XTAL_FREQ_COUNT 0x80 1413e9034789SMichal Meloun 1414e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1415e9034789SMichal Meloun reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; 1416e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1417e9034789SMichal Meloun 1418e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG2, ®); 1419e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); 1420e9034789SMichal Meloun reg |= UTMIP_PLL_CFG2_STABLE_COUNT(STABLE_COUNT); 1421e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); 1422e9034789SMichal Meloun reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(ACTIVE_DELAY_COUNT); 1423e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG2, reg); 1424e9034789SMichal Meloun 1425e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®); 1426e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); 1427e9034789SMichal Meloun reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(ENABLE_DELAY_COUNT); 1428e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); 1429e9034789SMichal Meloun reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(XTAL_FREQ_COUNT); 1430e9034789SMichal Meloun reg |= UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP; 1431e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg); 1432e9034789SMichal Meloun 1433e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; 1434e9034789SMichal Meloun reg |= UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; 1435e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg); 1436e9034789SMichal Meloun DELAY(20); 1437e9034789SMichal Meloun 1438e9034789SMichal Meloun /* Setup samplers. */ 1439e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG2, ®); 1440e9034789SMichal Meloun reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERUP; 1441e9034789SMichal Meloun reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERUP; 1442e9034789SMichal Meloun reg |= UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERUP; 1443e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; 1444e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; 1445e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_D_POWERDOWN; 1446e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG2, reg); 1447e9034789SMichal Meloun 1448e9034789SMichal Meloun /* Powerup UTMIP. */ 1449e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIP_PLL_CFG1, ®); 1450e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; 1451e9034789SMichal Meloun reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; 1452e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIP_PLL_CFG1, reg); 1453e9034789SMichal Meloun DELAY(10); 1454e9034789SMichal Meloun 1455e9034789SMichal Meloun /* Prepare UTMIP sequencer. */ 1456e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1457e9034789SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; 1458e9034789SMichal Meloun reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; 1459e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1460e9034789SMichal Meloun DELAY(10); 1461e9034789SMichal Meloun 1462e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, XUSB_PLL_CFG0, ®); 1463e9034789SMichal Meloun reg &= ~XUSB_PLL_CFG0_UTMIPLL_LOCK_DLY; 1464e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, XUSB_PLL_CFG0, reg); 1465e9034789SMichal Meloun DELAY(10); 1466e9034789SMichal Meloun 1467e9034789SMichal Meloun /* HW control of UTMIPLL. */ 1468e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, ®); 1469e9034789SMichal Meloun reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; 1470e9034789SMichal Meloun CLKDEV_WRITE_4(sc->dev, UTMIPLL_HW_PWRDN_CFG0, reg); 1471e9034789SMichal Meloun } 1472e9034789SMichal Meloun 1473e9034789SMichal Meloun void 1474e9034789SMichal Meloun tegra210_init_plls(struct tegra210_car_softc *sc) 1475e9034789SMichal Meloun { 1476e9034789SMichal Meloun int i, rv; 1477e9034789SMichal Meloun 1478e9034789SMichal Meloun for (i = 0; i < nitems(tegra210_pll_sources); i++) { 1479e9034789SMichal Meloun rv = clknode_mux_register(sc->clkdom, tegra210_pll_sources + i); 1480e9034789SMichal Meloun if (rv != 0) 1481e9034789SMichal Meloun panic("clk_mux_register failed"); 1482e9034789SMichal Meloun } 1483e9034789SMichal Meloun 1484e9034789SMichal Meloun for (i = 0; i < nitems(pll_clks); i++) { 1485e9034789SMichal Meloun rv = pll_register(sc->clkdom, pll_clks + i); 1486e9034789SMichal Meloun if (rv != 0) 1487e9034789SMichal Meloun panic("pll_register failed"); 1488e9034789SMichal Meloun } 1489e9034789SMichal Meloun 1490e9034789SMichal Meloun config_utmi_pll(sc); 1491e9034789SMichal Meloun 1492e9034789SMichal Meloun for (i = 0; i < nitems(tegra210_pll_fdivs); i++) { 1493e9034789SMichal Meloun rv = clknode_fixed_register(sc->clkdom, tegra210_pll_fdivs + i); 1494e9034789SMichal Meloun if (rv != 0) 1495e9034789SMichal Meloun panic("clk_fixed_register failed"); 1496e9034789SMichal Meloun } 1497e9034789SMichal Meloun 1498e9034789SMichal Meloun for (i = 0; i < nitems(tegra210_pll_gates); i++) { 1499e9034789SMichal Meloun rv = clknode_gate_register(sc->clkdom, tegra210_pll_gates + i); 1500e9034789SMichal Meloun if (rv != 0) 1501e9034789SMichal Meloun panic("clk_gate_register failed"); 1502e9034789SMichal Meloun } 1503e9034789SMichal Meloun 1504e9034789SMichal Meloun for (i = 0; i < nitems(tegra210_pll_divs); i++) { 1505e9034789SMichal Meloun rv = clknode_div_register(sc->clkdom, tegra210_pll_divs + i); 1506e9034789SMichal Meloun if (rv != 0) 1507e9034789SMichal Meloun panic("clk_div_register failed"); 1508e9034789SMichal Meloun } 1509e9034789SMichal Meloun } 1510