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