1296936Smmel/*-
2296936Smmel * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3296936Smmel * All rights reserved.
4296936Smmel *
5296936Smmel * Redistribution and use in source and binary forms, with or without
6296936Smmel * modification, are permitted provided that the following conditions
7296936Smmel * are met:
8296936Smmel * 1. Redistributions of source code must retain the above copyright
9296936Smmel *    notice, this list of conditions and the following disclaimer.
10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright
11296936Smmel *    notice, this list of conditions and the following disclaimer in the
12296936Smmel *    documentation and/or other materials provided with the distribution.
13296936Smmel *
14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17296936Smmel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24296936Smmel * SUCH DAMAGE.
25296936Smmel */
26296936Smmel
27296936Smmel#include <sys/cdefs.h>
28296936Smmel__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra124/tegra124_car.c 317013 2017-04-16 08:21:14Z mmel $");
29296936Smmel
30296936Smmel#include <sys/param.h>
31296936Smmel#include <sys/systm.h>
32296936Smmel#include <sys/bus.h>
33296936Smmel#include <sys/kernel.h>
34296936Smmel#include <sys/kobj.h>
35296936Smmel#include <sys/module.h>
36296936Smmel#include <sys/malloc.h>
37296936Smmel#include <sys/rman.h>
38296936Smmel#include <sys/lock.h>
39296936Smmel#include <sys/mutex.h>
40296936Smmel
41296936Smmel#include <machine/bus.h>
42296936Smmel#include <machine/cpu.h>
43296936Smmel
44296936Smmel#include <dev/extres/clk/clk_div.h>
45296936Smmel#include <dev/extres/clk/clk_fixed.h>
46296936Smmel#include <dev/extres/clk/clk_gate.h>
47296936Smmel#include <dev/extres/clk/clk_mux.h>
48296936Smmel#include <dev/extres/hwreset/hwreset.h>
49296936Smmel#include <dev/ofw/openfirm.h>
50296936Smmel#include <dev/ofw/ofw_bus.h>
51296936Smmel#include <dev/ofw/ofw_bus_subr.h>
52296936Smmel
53296936Smmel#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h>
54296936Smmel
55296936Smmel#include "clkdev_if.h"
56296936Smmel#include "hwreset_if.h"
57296936Smmel#include "tegra124_car.h"
58296936Smmel
59296936Smmelstatic struct ofw_compat_data compat_data[] = {
60296936Smmel	{"nvidia,tegra124-car",	1},
61296936Smmel	{NULL,		 	0},
62296936Smmel};
63296936Smmel
64296936Smmel#define	PLIST(x) static const char *x[]
65296936Smmel
66296936Smmel/* Pure multiplexer. */
67296936Smmel#define	MUX(_id, cname, plists, o, s, w)				\
68296936Smmel{									\
69296936Smmel	.clkdef.id = _id,						\
70296936Smmel	.clkdef.name = cname,						\
71296936Smmel	.clkdef.parent_names = plists,					\
72296936Smmel	.clkdef.parent_cnt = nitems(plists),				\
73296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
74296936Smmel	.offset = o,							\
75296936Smmel	.shift  = s,							\
76296936Smmel	.width = w,							\
77296936Smmel}
78296936Smmel
79296936Smmel/* Fractional divider (7.1). */
80296936Smmel#define	DIV7_1(_id, cname, plist, o, s)					\
81296936Smmel{									\
82296936Smmel	.clkdef.id = _id,						\
83296936Smmel	.clkdef.name = cname,						\
84296936Smmel	.clkdef.parent_names = (const char *[]){plist},			\
85296936Smmel	.clkdef.parent_cnt = 1,						\
86296936Smmel	.clkdef.flags =  CLK_NODE_STATIC_STRINGS,			\
87296936Smmel	.offset = o,							\
88296936Smmel	.i_shift = (s) + 1,						\
89296936Smmel	.i_width = 7,							\
90296936Smmel	.f_shift = s,							\
91296936Smmel	.f_width = 1,							\
92296936Smmel}
93296936Smmel
94296936Smmel/* Integer divider. */
95296936Smmel#define	DIV(_id, cname, plist, o, s, w, f)				\
96296936Smmel{									\
97296936Smmel	.clkdef.id = _id,						\
98296936Smmel	.clkdef.name = cname,						\
99296936Smmel	.clkdef.parent_names = (const char *[]){plist},			\
100296936Smmel	.clkdef.parent_cnt = 1,						\
101296936Smmel	.clkdef.flags =  CLK_NODE_STATIC_STRINGS,			\
102296936Smmel	.offset = o,							\
103296936Smmel	.i_shift = s,							\
104296936Smmel	.i_width = w,							\
105296936Smmel	.div_flags = f,							\
106296936Smmel}
107296936Smmel
108296936Smmel/* Gate in PLL block. */
109296936Smmel#define	GATE_PLL(_id, cname, plist, o, s)				\
110296936Smmel{									\
111296936Smmel	.clkdef.id = _id,						\
112296936Smmel	.clkdef.name = cname,						\
113296936Smmel	.clkdef.parent_names = (const char *[]){plist},			\
114296936Smmel	.clkdef.parent_cnt = 1,						\
115296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
116296936Smmel	.offset = o,							\
117296936Smmel	.shift = s,							\
118296936Smmel	.mask = 3,							\
119296936Smmel	.on_value = 3,							\
120296936Smmel	.off_value = 0,							\
121296936Smmel}
122296936Smmel
123296936Smmel/* Standard gate. */
124296936Smmel#define	GATE(_id, cname, plist, o, s)					\
125296936Smmel{									\
126296936Smmel	.clkdef.id = _id,						\
127296936Smmel	.clkdef.name = cname,						\
128296936Smmel	.clkdef.parent_names = (const char *[]){plist},			\
129296936Smmel	.clkdef.parent_cnt = 1,						\
130296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
131296936Smmel	.offset = o,							\
132296936Smmel	.shift = s,							\
133296936Smmel	.mask = 1,							\
134296936Smmel	.on_value = 1,							\
135296936Smmel	.off_value = 0,							\
136296936Smmel}
137296936Smmel
138296936Smmel/* Inverted gate. */
139296936Smmel#define	GATE_INV(_id, cname, plist, o, s)				\
140296936Smmel{									\
141296936Smmel	.clkdef.id = _id,						\
142296936Smmel	.clkdef.name = cname,						\
143296936Smmel	.clkdef.parent_names = (const char *[]){plist},			\
144296936Smmel	.clkdef.parent_cnt = 1,						\
145296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
146296936Smmel	.offset = o,							\
147296936Smmel	.shift = s,							\
148296936Smmel	.mask = 1,							\
149296936Smmel	.on_value = 0,							\
150296936Smmel	.off_value = 1,							\
151296936Smmel}
152296936Smmel
153296936Smmel/* Fixed rate clock. */
154296936Smmel#define	FRATE(_id, cname, _freq)					\
155296936Smmel{									\
156296936Smmel	.clkdef.id = _id,						\
157296936Smmel	.clkdef.name = cname,						\
158296936Smmel	.clkdef.parent_names = NULL,					\
159296936Smmel	.clkdef.parent_cnt = 0,						\
160296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
161296936Smmel	.freq = _freq,							\
162296936Smmel}
163296936Smmel
164296936Smmel/* Fixed rate multipier/divider. */
165296936Smmel#define	FACT(_id, cname, pname, _mult, _div)				\
166296936Smmel{									\
167296936Smmel	.clkdef.id = _id,						\
168296936Smmel	.clkdef.name = cname,						\
169296936Smmel	.clkdef.parent_names = (const char *[]){pname},			\
170296936Smmel	.clkdef.parent_cnt = 1,						\
171296936Smmel	.clkdef.flags = CLK_NODE_STATIC_STRINGS,			\
172296936Smmel	.mult = _mult,							\
173296936Smmel	.div = _div,							\
174296936Smmel}
175296936Smmel
176296936Smmelstatic uint32_t osc_freqs[16] = {
177296936Smmel	 [0] =  13000000,
178296936Smmel	 [1] =  16800000,
179296936Smmel	 [4] =  19200000,
180296936Smmel	 [5] =  38400000,
181296936Smmel	 [8] =  12000000,
182296936Smmel	 [9] =  48000000,
183296936Smmel	[12] = 260000000,
184296936Smmel};
185296936Smmel
186296936Smmel
187296936Smmel/* Parent lists. */
188296936SmmelPLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */
189296936SmmelPLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"};
190296936SmmelPLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"};
191296936SmmelPLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"};
192317012SmmelPLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60"};
193296936SmmelPLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"};
194296936Smmel
195296936Smmel
196296936Smmel/* Clocks ajusted online. */
197296936Smmelstatic struct clk_fixed_def fixed_clk_m =
198317012Smmel	FRATE(TEGRA124_CLK_CLK_M, "clk_m", 12000000);
199296936Smmelstatic struct clk_fixed_def fixed_osc_div_clk =
200296936Smmel	FACT(0, "osc_div_clk", "clk_m", 1, 1);
201296936Smmel
202296936Smmelstatic struct clk_fixed_def tegra124_fixed_clks[] = {
203296936Smmel	/* Core clocks. */
204296936Smmel	FRATE(0, "clk_s", 32768),
205296936Smmel	FACT(0, "clk_m_div2", "clk_m", 1, 2),
206296936Smmel	FACT(0, "clk_m_div4", "clk_m", 1, 3),
207296936Smmel	FACT(0, "pllU_60", "pllU_out", 1, 8),
208296936Smmel	FACT(0, "pllU_48", "pllU_out", 1, 10),
209296936Smmel	FACT(0, "pllU_12", "pllU_out", 1, 40),
210296936Smmel	FACT(TEGRA124_CLK_PLL_D_OUT0, "pllD_out0", "pllD_out", 1, 2),
211296936Smmel	FACT(TEGRA124_CLK_PLL_D2_OUT0, "pllD2_out0", "pllD2_out", 1, 1),
212296936Smmel	FACT(0, "pllX_out0", "pllX_out", 1, 2),
213296936Smmel	FACT(0, "pllC_UD", "pllC_out0", 1, 1),
214296936Smmel	FACT(0, "pllM_UD", "pllM_out0", 1, 1),
215296936Smmel
216296936Smmel	/* Audio clocks. */
217296936Smmel	FRATE(0, "audio0", 10000000),
218296936Smmel	FRATE(0, "audio1", 10000000),
219296936Smmel	FRATE(0, "audio2", 10000000),
220296936Smmel	FRATE(0, "audio3", 10000000),
221296936Smmel	FRATE(0, "audio4", 10000000),
222296936Smmel	FRATE(0, "ext_vimclk", 10000000),
223317012Smmel
224317012Smmel	/* XUSB */
225317012Smmel	FACT(TEGRA124_CLK_XUSB_SS_DIV2, "xusb_ss_div2", "xusb_ss", 1, 2),
226317012Smmel
227296936Smmel};
228296936Smmel
229296936Smmel
230296936Smmelstatic struct clk_mux_def tegra124_mux_clks[] = {
231296936Smmel	/* Core clocks. */
232296936Smmel	MUX(0, "pllD2_src", mux_pll_srcs, PLLD2_BASE, 25, 2),
233296936Smmel	MUX(0, "pllDP_src", mux_pll_srcs, PLLDP_BASE, 25, 2),
234296936Smmel	MUX(0, "pllC4_src", mux_pll_srcs, PLLC4_BASE, 25, 2),
235296936Smmel	MUX(0, "pllE_src1", mux_plle_src1, PLLE_AUX, 2, 1),
236296936Smmel	MUX(0, "pllE_src",  mux_plle_src, PLLE_AUX, 28, 1),
237296936Smmel
238296936Smmel	/* Base peripheral clocks. */
239296936Smmel	MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1),
240296936Smmel	MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1),
241296936Smmel
242296936Smmel	/* USB. */
243317012Smmel	MUX(TEGRA124_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1),
244296936Smmel	MUX(0, "xusb_ss_mux", mux_xusb_ss, CLK_SOURCE_XUSB_SS, 24, 1),
245296936Smmel
246296936Smmel};
247296936Smmel
248296936Smmel
249296936Smmelstatic struct clk_gate_def tegra124_gate_clks[] = {
250296936Smmel	/* Core clocks. */
251296936Smmel	GATE_PLL(0, "pllC_out1", "pllC_out1_div", PLLC_OUT, 0),
252296936Smmel	GATE_PLL(0, "pllM_out1", "pllM_out1_div", PLLM_OUT, 0),
253317012Smmel	GATE_PLL(TEGRA124_CLK_PLL_U_480M, "pllU_480", "pllU_out", PLLU_BASE, 22),
254296936Smmel	GATE_PLL(0, "pllP_outX0", "pllP_outX0_div", PLLP_RESHIFT, 0),
255296936Smmel	GATE_PLL(0, "pllP_out1", "pllP_out1_div", PLLP_OUTA, 0),
256296936Smmel	GATE_PLL(0, "pllP_out2", "pllP_out2_div", PLLP_OUTA, 16),
257296936Smmel	GATE_PLL(0, "pllP_out3", "pllP_out3_div", PLLP_OUTB, 0),
258296936Smmel	GATE_PLL(0, "pllP_out4", "pllP_out4_div", PLLP_OUTB, 16),
259296936Smmel	GATE_PLL(0, "pllP_out5", "pllP_out5_div", PLLP_OUTC, 16),
260296936Smmel	GATE_PLL(0, "pllA_out0", "pllA_out1_div", PLLA_OUT, 0),
261296936Smmel
262296936Smmel	/* Base peripheral clocks. */
263296936Smmel	GATE(TEGRA124_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0),
264296936Smmel	GATE(TEGRA124_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1),
265296936Smmel	GATE_INV(TEGRA124_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7),
266296936Smmel	GATE_INV(TEGRA124_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3),
267296936Smmel};
268296936Smmel
269296936Smmelstatic struct clk_div_def tegra124_div_clks[] = {
270296936Smmel	/* Core clocks. */
271296936Smmel	DIV7_1(0, "pllC_out1_div", "pllC_out0", PLLC_OUT, 2),
272296936Smmel	DIV7_1(0, "pllM_out1_div", "pllM_out0", PLLM_OUT, 8),
273296936Smmel	DIV7_1(0, "pllP_outX0_div", "pllP_out0", PLLP_RESHIFT, 2),
274296936Smmel	DIV7_1(0, "pllP_out1_div", "pllP_out0", PLLP_OUTA, 8),
275296936Smmel	DIV7_1(0, "pllP_out2_div", "pllP_out0", PLLP_OUTA, 24),
276296936Smmel	DIV7_1(0, "pllP_out3_div", "pllP_out0", PLLP_OUTB, 8),
277296936Smmel	DIV7_1(0, "pllP_out4_div", "pllP_out0", PLLP_OUTB, 24),
278296936Smmel	DIV7_1(0, "pllP_out5_div", "pllP_out0", PLLP_OUTC, 24),
279296936Smmel	DIV7_1(0, "pllA_out1_div", "pllA_out", PLLA_OUT, 8),
280296936Smmel
281296936Smmel	/* Base peripheral clocks. */
282296936Smmel	DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0),
283296936Smmel	DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0),
284296936Smmel};
285296936Smmel
286296936Smmel/* Initial setup table. */
287296936Smmelstatic struct  tegra124_init_item clk_init_table[] = {
288296936Smmel	/* clock, partent, frequency, enable */
289296936Smmel	{"uarta", "pllP_out0", 408000000, 0},
290296936Smmel	{"uartb", "pllP_out0", 408000000, 0},
291296936Smmel	{"uartc", "pllP_out0", 408000000, 0},
292296936Smmel	{"uartd", "pllP_out0", 408000000, 0},
293296936Smmel	{"pllA_out", NULL, 282240000, 1},
294296936Smmel	{"pllA_out0", NULL, 11289600, 1},
295296936Smmel	{"extperiph1", "pllA_out0", 0, 1},
296296936Smmel	{"i2s0", "pllA_out0", 11289600, 0},
297296936Smmel	{"i2s1", "pllA_out0", 11289600, 0},
298296936Smmel	{"i2s2", "pllA_out0", 11289600, 0},
299296936Smmel	{"i2s3", "pllA_out0", 11289600, 0},
300296936Smmel	{"i2s4", "pllA_out0", 11289600, 0},
301296936Smmel	{"vde", "pllP_out0", 0, 0},
302296936Smmel	{"host1x", "pllP_out0", 136000000, 1},
303296936Smmel	{"sclk", "pllP_out2", 102000000, 1},
304296936Smmel	{"dvfs_soc", "pllP_out0", 51000000, 1},
305296936Smmel	{"dvfs_ref", "pllP_out0", 51000000, 1},
306296936Smmel	{"pllC_out0", NULL, 600000000, 0},
307296936Smmel	{"pllC_out1", NULL, 100000000, 0},
308296936Smmel	{"spi4", "pllP_out0", 12000000, 1},
309296936Smmel	{"tsec", "pllC3_out0", 0, 0},
310296936Smmel	{"msenc", "pllC3_out0", 0, 0},
311296936Smmel	{"pllREFE_out", NULL, 672000000, 0},
312296936Smmel	{"pc_xusb_ss", "pllU_480", 120000000, 0},
313296936Smmel	{"xusb_ss", "pc_xusb_ss", 120000000, 0},
314296936Smmel	{"pc_xusb_fs", "pllU_48", 48000000, 0},
315296936Smmel	{"xusb_hs", "pllU_60", 60000000, 0},
316296936Smmel	{"pc_xusb_falcon", "pllREFE_out", 224000000, 0},
317296936Smmel	{"xusb_core_host", "pllREFE_out", 112000000, 0},
318296936Smmel	{"sata", "pllP_out0", 102000000, 0},
319296936Smmel	{"sata_oob", "pllP_out0", 204000000, 0},
320296936Smmel	{"sata_cold", NULL, 0, 1},
321296936Smmel	{"emc", NULL, 0, 1},
322296936Smmel	{"mselect", NULL, 0, 1},
323296936Smmel	{"csite", NULL, 0, 1},
324296936Smmel	{"tsensor", "clk_m", 400000, 0},
325296936Smmel
326296936Smmel	/* tegra124 only*/
327296936Smmel	{"soc_therm", "pllP_out0", 51000000, 0},
328296936Smmel	{"cclk_g", NULL, 0, 1},
329296936Smmel	{"hda", "pllP_out0", 102000000, 0},
330296936Smmel	{"hda2codec_2x", "pllP_out0", 48000000, 0},
331296936Smmel};
332296936Smmel
333296936Smmelstatic void
334296936Smmelinit_divs(struct tegra124_car_softc *sc, struct clk_div_def *clks, int nclks)
335296936Smmel{
336296936Smmel	int i, rv;
337296936Smmel
338296936Smmel	for (i = 0; i < nclks; i++) {
339296936Smmel		rv = clknode_div_register(sc->clkdom, clks + i);
340296936Smmel		if (rv != 0)
341296936Smmel			panic("clk_div_register failed");
342296936Smmel	}
343296936Smmel}
344296936Smmel
345296936Smmelstatic void
346296936Smmelinit_gates(struct tegra124_car_softc *sc, struct clk_gate_def *clks, int nclks)
347296936Smmel{
348296936Smmel	int i, rv;
349296936Smmel
350296936Smmel
351296936Smmel	for (i = 0; i < nclks; i++) {
352296936Smmel		rv = clknode_gate_register(sc->clkdom, clks + i);
353296936Smmel		if (rv != 0)
354296936Smmel			panic("clk_gate_register failed");
355296936Smmel	}
356296936Smmel}
357296936Smmel
358296936Smmelstatic void
359296936Smmelinit_muxes(struct tegra124_car_softc *sc, struct clk_mux_def *clks, int nclks)
360296936Smmel{
361296936Smmel	int i, rv;
362296936Smmel
363296936Smmel
364296936Smmel	for (i = 0; i < nclks; i++) {
365296936Smmel		rv = clknode_mux_register(sc->clkdom, clks + i);
366296936Smmel		if (rv != 0)
367296936Smmel			panic("clk_mux_register failed");
368296936Smmel	}
369296936Smmel}
370296936Smmel
371296936Smmelstatic void
372296936Smmelinit_fixeds(struct tegra124_car_softc *sc, struct clk_fixed_def *clks,
373296936Smmel    int nclks)
374296936Smmel{
375296936Smmel	int i, rv;
376296936Smmel	uint32_t val;
377296936Smmel	int osc_idx;
378296936Smmel
379296936Smmel	CLKDEV_READ_4(sc->dev, OSC_CTRL, &val);
380296936Smmel	osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;
381296936Smmel	fixed_clk_m.freq = osc_freqs[osc_idx];
382296936Smmel	if (fixed_clk_m.freq == 0)
383296936Smmel		panic("Undefined input frequency");
384296936Smmel	rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m);
385296936Smmel	if (rv != 0) panic("clk_fixed_register failed");
386296936Smmel
387296936Smmel	val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
388296936Smmel	fixed_osc_div_clk.div = 1 << val;
389296936Smmel	rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div_clk);
390296936Smmel	if (rv != 0) panic("clk_fixed_register failed");
391296936Smmel
392296936Smmel	for (i = 0; i < nclks; i++) {
393296936Smmel		rv = clknode_fixed_register(sc->clkdom, clks + i);
394296936Smmel		if (rv != 0)
395296936Smmel			panic("clk_fixed_register failed");
396296936Smmel	}
397296936Smmel}
398296936Smmel
399296936Smmelstatic void
400296936Smmelpostinit_clock(struct tegra124_car_softc *sc)
401296936Smmel{
402296936Smmel	int i;
403296936Smmel	struct tegra124_init_item *tbl;
404296936Smmel	struct clknode *clknode;
405296936Smmel	int rv;
406296936Smmel
407296936Smmel	for (i = 0; i < nitems(clk_init_table); i++) {
408296936Smmel		tbl = &clk_init_table[i];
409296936Smmel
410296936Smmel		clknode =  clknode_find_by_name(tbl->name);
411296936Smmel		if (clknode == NULL) {
412296936Smmel			device_printf(sc->dev, "Cannot find clock %s\n",
413296936Smmel			    tbl->name);
414296936Smmel			continue;
415296936Smmel		}
416296936Smmel		if (tbl->parent != NULL) {
417296936Smmel			rv = clknode_set_parent_by_name(clknode, tbl->parent);
418296936Smmel			if (rv != 0) {
419296936Smmel				device_printf(sc->dev,
420296936Smmel				    "Cannot set parent for %s (to %s): %d\n",
421296936Smmel				    tbl->name, tbl->parent, rv);
422296936Smmel				continue;
423296936Smmel			}
424296936Smmel		}
425296936Smmel		if (tbl->frequency != 0) {
426296936Smmel			rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999);
427296936Smmel			if (rv != 0) {
428296936Smmel				device_printf(sc->dev,
429296936Smmel				    "Cannot set frequency for %s: %d\n",
430296936Smmel				    tbl->name, rv);
431296936Smmel				continue;
432296936Smmel			}
433296936Smmel		}
434296936Smmel		if (tbl->enable!= 0) {
435296936Smmel			rv = clknode_enable(clknode);
436296936Smmel			if (rv != 0) {
437296936Smmel				device_printf(sc->dev,
438296936Smmel				    "Cannot enable %s: %d\n", tbl->name, rv);
439296936Smmel				continue;
440296936Smmel			}
441296936Smmel		}
442296936Smmel	}
443296936Smmel}
444296936Smmel
445296936Smmelstatic void
446296936Smmelregister_clocks(device_t dev)
447296936Smmel{
448296936Smmel	struct tegra124_car_softc *sc;
449296936Smmel
450296936Smmel	sc = device_get_softc(dev);
451296936Smmel	sc->clkdom = clkdom_create(dev);
452296936Smmel	if (sc->clkdom == NULL)
453296936Smmel		panic("clkdom == NULL");
454296936Smmel
455296936Smmel	tegra124_init_plls(sc);
456296936Smmel	init_fixeds(sc, tegra124_fixed_clks, nitems(tegra124_fixed_clks));
457296936Smmel	init_muxes(sc, tegra124_mux_clks, nitems(tegra124_mux_clks));
458296936Smmel	init_divs(sc, tegra124_div_clks, nitems(tegra124_div_clks));
459296936Smmel	init_gates(sc, tegra124_gate_clks, nitems(tegra124_gate_clks));
460296936Smmel	tegra124_periph_clock(sc);
461296936Smmel	tegra124_super_mux_clock(sc);
462296936Smmel	clkdom_finit(sc->clkdom);
463296936Smmel	clkdom_xlock(sc->clkdom);
464296936Smmel	postinit_clock(sc);
465296936Smmel	clkdom_unlock(sc->clkdom);
466296936Smmel	if (bootverbose)
467296936Smmel		clkdom_dump(sc->clkdom);
468296936Smmel}
469296936Smmel
470296936Smmelstatic int
471296936Smmeltegra124_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
472296936Smmel{
473296936Smmel	struct tegra124_car_softc *sc;
474296936Smmel
475296936Smmel	sc = device_get_softc(dev);
476296936Smmel	*val = bus_read_4(sc->mem_res, addr);
477296936Smmel	return (0);
478296936Smmel}
479296936Smmel
480296936Smmelstatic int
481296936Smmeltegra124_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val)
482296936Smmel{
483296936Smmel	struct tegra124_car_softc *sc;
484296936Smmel
485296936Smmel	sc = device_get_softc(dev);
486296936Smmel	bus_write_4(sc->mem_res, addr, val);
487296936Smmel	return (0);
488296936Smmel}
489296936Smmel
490296936Smmelstatic int
491296936Smmeltegra124_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
492296936Smmel    uint32_t set_mask)
493296936Smmel{
494296936Smmel	struct tegra124_car_softc *sc;
495296936Smmel	uint32_t reg;
496296936Smmel
497296936Smmel	sc = device_get_softc(dev);
498296936Smmel	reg = bus_read_4(sc->mem_res, addr);
499296936Smmel	reg &= ~clear_mask;
500296936Smmel	reg |= set_mask;
501296936Smmel	bus_write_4(sc->mem_res, addr, reg);
502296936Smmel	return (0);
503296936Smmel}
504296936Smmel
505296936Smmelstatic void
506296936Smmeltegra124_car_clkdev_device_lock(device_t dev)
507296936Smmel{
508296936Smmel	struct tegra124_car_softc *sc;
509296936Smmel
510296936Smmel	sc = device_get_softc(dev);
511296936Smmel	mtx_lock(&sc->mtx);
512296936Smmel}
513296936Smmel
514296936Smmelstatic void
515296936Smmeltegra124_car_clkdev_device_unlock(device_t dev)
516296936Smmel{
517296936Smmel	struct tegra124_car_softc *sc;
518296936Smmel
519296936Smmel	sc = device_get_softc(dev);
520296936Smmel	mtx_unlock(&sc->mtx);
521296936Smmel}
522296936Smmel
523296936Smmelstatic int
524296936Smmeltegra124_car_detach(device_t dev)
525296936Smmel{
526296936Smmel
527296936Smmel	device_printf(dev, "Error: Clock driver cannot be detached\n");
528296936Smmel	return (EBUSY);
529296936Smmel}
530296936Smmel
531296936Smmelstatic int
532296936Smmeltegra124_car_probe(device_t dev)
533296936Smmel{
534296936Smmel
535296936Smmel	if (!ofw_bus_status_okay(dev))
536296936Smmel		return (ENXIO);
537296936Smmel
538296936Smmel	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
539296936Smmel		device_set_desc(dev, "Tegra Clock Driver");
540296936Smmel		return (BUS_PROBE_DEFAULT);
541296936Smmel	}
542296936Smmel
543296936Smmel	return (ENXIO);
544296936Smmel}
545296936Smmel
546296936Smmelstatic int
547296936Smmeltegra124_car_attach(device_t dev)
548296936Smmel{
549296936Smmel	struct tegra124_car_softc *sc = device_get_softc(dev);
550296936Smmel	int rid, rv;
551296936Smmel
552296936Smmel	sc->dev = dev;
553296936Smmel
554296936Smmel	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
555296936Smmel	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
556296936Smmel
557296936Smmel	/* Resource setup. */
558296936Smmel	rid = 0;
559296936Smmel	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
560296936Smmel	    RF_ACTIVE);
561296936Smmel	if (!sc->mem_res) {
562296936Smmel		device_printf(dev, "cannot allocate memory resource\n");
563296936Smmel		rv = ENXIO;
564296936Smmel		goto fail;
565296936Smmel	}
566296936Smmel
567296936Smmel	register_clocks(dev);
568296936Smmel	hwreset_register_ofw_provider(dev);
569296936Smmel	return (0);
570296936Smmel
571296936Smmelfail:
572296936Smmel	if (sc->mem_res)
573296936Smmel		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
574296936Smmel
575296936Smmel	return (rv);
576296936Smmel}
577296936Smmel
578296936Smmelstatic int
579296936Smmeltegra124_car_hwreset_assert(device_t dev, intptr_t id, bool value)
580296936Smmel{
581296936Smmel	struct tegra124_car_softc *sc = device_get_softc(dev);
582296936Smmel
583296936Smmel	return (tegra124_hwreset_by_idx(sc, id, value));
584296936Smmel}
585296936Smmel
586296936Smmelstatic device_method_t tegra124_car_methods[] = {
587296936Smmel	/* Device interface */
588296936Smmel	DEVMETHOD(device_probe,		tegra124_car_probe),
589296936Smmel	DEVMETHOD(device_attach,	tegra124_car_attach),
590296936Smmel	DEVMETHOD(device_detach,	tegra124_car_detach),
591296936Smmel
592296936Smmel	/* Clkdev  interface*/
593296936Smmel	DEVMETHOD(clkdev_read_4,	tegra124_car_clkdev_read_4),
594296936Smmel	DEVMETHOD(clkdev_write_4,	tegra124_car_clkdev_write_4),
595296936Smmel	DEVMETHOD(clkdev_modify_4,	tegra124_car_clkdev_modify_4),
596296936Smmel	DEVMETHOD(clkdev_device_lock,	tegra124_car_clkdev_device_lock),
597296936Smmel	DEVMETHOD(clkdev_device_unlock,	tegra124_car_clkdev_device_unlock),
598296936Smmel
599296936Smmel	/* Reset interface */
600296936Smmel	DEVMETHOD(hwreset_assert,	tegra124_car_hwreset_assert),
601296936Smmel
602296936Smmel	DEVMETHOD_END
603296936Smmel};
604296936Smmel
605296936Smmelstatic devclass_t tegra124_car_devclass;
606308335Smmelstatic DEFINE_CLASS_0(car, tegra124_car_driver, tegra124_car_methods,
607308335Smmel    sizeof(struct tegra124_car_softc));
608296936SmmelEARLY_DRIVER_MODULE(tegra124_car, simplebus, tegra124_car_driver,
609308335Smmel    tegra124_car_devclass, NULL, NULL, BUS_PASS_TIMER);
610