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, &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, &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, &reg);
522ef2ee5d0SMichal Meloun 		reg &=  PLLRE_MISC_LOCK;
523ef2ee5d0SMichal Meloun 		break;
524ef2ee5d0SMichal Meloun 
525ef2ee5d0SMichal Meloun 	case PLL_E:
526ef2ee5d0SMichal Meloun 		RD4(sc, sc->misc_reg, &reg);
527ef2ee5d0SMichal Meloun 		reg &= PLLE_MISC_LOCK;
528ef2ee5d0SMichal Meloun 		break;
529ef2ee5d0SMichal Meloun 
530ef2ee5d0SMichal Meloun 	default:
531ef2ee5d0SMichal Meloun 		RD4(sc, sc->base_reg, &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, &reg);
567ef2ee5d0SMichal Meloun 	reg &= ~PLLE_BASE_LOCK_OVERRIDE;
568ef2ee5d0SMichal Meloun 	WR4(sc, sc->base_reg, reg);
569ef2ee5d0SMichal Meloun 
570ef2ee5d0SMichal Meloun 	RD4(sc, PLLE_AUX, &reg);
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, &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, &reg);
587ef2ee5d0SMichal Meloun 	reg |= PLLE_SS_CNTL_DISABLE;
588ef2ee5d0SMichal Meloun 	WR4(sc, PLLE_SS_CNTL, reg);
589ef2ee5d0SMichal Meloun 
590ef2ee5d0SMichal Meloun 	RD4(sc, sc->base_reg, &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, &reg);
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, &reg);
619ef2ee5d0SMichal Meloun 	reg &= ~PLLE_MISC_IDDQ_SWCTL;
620ef2ee5d0SMichal Meloun 	WR4(sc, sc->misc_reg, reg);
621ef2ee5d0SMichal Meloun 
622ef2ee5d0SMichal Meloun 	RD4(sc, PLLE_AUX, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &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, &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, &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, &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, &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, &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, &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, &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, &reg);
926ef2ee5d0SMichal Meloun 	DELAY(100);
927ef2ee5d0SMichal Meloun 
928b7997839SMichal Meloun 	/* Enable lock detection. */
929b7997839SMichal Meloun 	RD4(sc, sc->misc_reg, &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, &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, &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, &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, &reg);
1006ef2ee5d0SMichal Meloun 	if (reg & PLL_BASE_ENABLE) {
1007ef2ee5d0SMichal Meloun 		RD4(sc, sc->misc_reg, &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, &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, &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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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