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