1e9034789SMichal Meloun /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3e9034789SMichal Meloun *
4e9034789SMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5e9034789SMichal Meloun *
6e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without
7e9034789SMichal Meloun * modification, are permitted provided that the following conditions
8e9034789SMichal Meloun * are met:
9e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright
10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer.
11e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright
12e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the
13e9034789SMichal Meloun * documentation and/or other materials provided with the distribution.
14e9034789SMichal Meloun *
15e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e9034789SMichal Meloun * SUCH DAMAGE.
26e9034789SMichal Meloun */
27e9034789SMichal Meloun
28e9034789SMichal Meloun #include <sys/param.h>
29e9034789SMichal Meloun #include <sys/systm.h>
30e9034789SMichal Meloun #include <sys/bus.h>
31e9034789SMichal Meloun #include <sys/kernel.h>
32e9034789SMichal Meloun #include <sys/kobj.h>
33e9034789SMichal Meloun #include <sys/module.h>
34e9034789SMichal Meloun #include <sys/malloc.h>
35e9034789SMichal Meloun #include <sys/rman.h>
36e9034789SMichal Meloun #include <sys/lock.h>
37e9034789SMichal Meloun #include <sys/mutex.h>
38e9034789SMichal Meloun
39e9034789SMichal Meloun #include <machine/bus.h>
40e9034789SMichal Meloun #include <machine/cpu.h>
41e9034789SMichal Meloun
42be82b3a0SEmmanuel Vadot #include <dev/clk/clk_div.h>
43be82b3a0SEmmanuel Vadot #include <dev/clk/clk_fixed.h>
44be82b3a0SEmmanuel Vadot #include <dev/clk/clk_gate.h>
45be82b3a0SEmmanuel Vadot #include <dev/clk/clk_mux.h>
46*1f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
47e9034789SMichal Meloun #include <dev/ofw/openfirm.h>
48e9034789SMichal Meloun #include <dev/ofw/ofw_bus.h>
49e9034789SMichal Meloun #include <dev/ofw/ofw_bus_subr.h>
50e9034789SMichal Meloun
51c38fe878SEmmanuel Vadot #include <dt-bindings/clock/tegra210-car.h>
52e9034789SMichal Meloun
53e9034789SMichal Meloun #include "clkdev_if.h"
54e9034789SMichal Meloun #include "hwreset_if.h"
55e9034789SMichal Meloun #include "tegra210_car.h"
56e9034789SMichal Meloun
57e9034789SMichal Meloun static struct ofw_compat_data compat_data[] = {
58e9034789SMichal Meloun {"nvidia,tegra210-car", 1},
59e9034789SMichal Meloun {NULL, 0},
60e9034789SMichal Meloun };
61e9034789SMichal Meloun
62e9034789SMichal Meloun #define PLIST(x) static const char *x[]
63e9034789SMichal Meloun
64e9034789SMichal Meloun /* Pure multiplexer. */
65e9034789SMichal Meloun #define MUX(_id, cname, plists, o, s, w) \
66e9034789SMichal Meloun { \
67e9034789SMichal Meloun .clkdef.id = _id, \
68e9034789SMichal Meloun .clkdef.name = cname, \
69e9034789SMichal Meloun .clkdef.parent_names = plists, \
70e9034789SMichal Meloun .clkdef.parent_cnt = nitems(plists), \
71e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
72e9034789SMichal Meloun .offset = o, \
73e9034789SMichal Meloun .shift = s, \
74e9034789SMichal Meloun .width = w, \
75e9034789SMichal Meloun }
76e9034789SMichal Meloun
77e9034789SMichal Meloun /* Fractional divider (7.1). */
78e9034789SMichal Meloun #define DIV7_1(_id, cname, plist, o, s) \
79e9034789SMichal Meloun { \
80e9034789SMichal Meloun .clkdef.id = _id, \
81e9034789SMichal Meloun .clkdef.name = cname, \
82e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \
83e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
84e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
85e9034789SMichal Meloun .offset = o, \
86e9034789SMichal Meloun .i_shift = (s) + 1, \
87e9034789SMichal Meloun .i_width = 7, \
88e9034789SMichal Meloun .f_shift = s, \
89e9034789SMichal Meloun .f_width = 1, \
90e9034789SMichal Meloun }
91e9034789SMichal Meloun
92e9034789SMichal Meloun /* Integer divider. */
93e9034789SMichal Meloun #define DIV(_id, cname, plist, o, s, w, f) \
94e9034789SMichal Meloun { \
95e9034789SMichal Meloun .clkdef.id = _id, \
96e9034789SMichal Meloun .clkdef.name = cname, \
97e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \
98e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
99e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
100e9034789SMichal Meloun .offset = o, \
101e9034789SMichal Meloun .i_shift = s, \
102e9034789SMichal Meloun .i_width = w, \
103e9034789SMichal Meloun .div_flags = f, \
104e9034789SMichal Meloun }
105e9034789SMichal Meloun
106e9034789SMichal Meloun /* Gate in PLL block. */
107e9034789SMichal Meloun #define GATE_PLL(_id, cname, plist, o, s) \
108e9034789SMichal Meloun { \
109e9034789SMichal Meloun .clkdef.id = _id, \
110e9034789SMichal Meloun .clkdef.name = cname, \
111e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \
112e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
113e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
114e9034789SMichal Meloun .offset = o, \
115e9034789SMichal Meloun .shift = s, \
116e9034789SMichal Meloun .mask = 3, \
117e9034789SMichal Meloun .on_value = 3, \
118e9034789SMichal Meloun .off_value = 0, \
119e9034789SMichal Meloun }
120e9034789SMichal Meloun
121e9034789SMichal Meloun /* Standard gate. */
122e9034789SMichal Meloun #define GATE(_id, cname, plist, o, s) \
123e9034789SMichal Meloun { \
124e9034789SMichal Meloun .clkdef.id = _id, \
125e9034789SMichal Meloun .clkdef.name = cname, \
126e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \
127e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
128e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
129e9034789SMichal Meloun .offset = o, \
130e9034789SMichal Meloun .shift = s, \
131e9034789SMichal Meloun .mask = 1, \
132e9034789SMichal Meloun .on_value = 1, \
133e9034789SMichal Meloun .off_value = 0, \
134e9034789SMichal Meloun }
135e9034789SMichal Meloun
136e9034789SMichal Meloun /* Inverted gate. */
137e9034789SMichal Meloun #define GATE_INV(_id, cname, plist, o, s) \
138e9034789SMichal Meloun { \
139e9034789SMichal Meloun .clkdef.id = _id, \
140e9034789SMichal Meloun .clkdef.name = cname, \
141e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){plist}, \
142e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
143e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
144e9034789SMichal Meloun .offset = o, \
145e9034789SMichal Meloun .shift = s, \
146e9034789SMichal Meloun .mask = 1, \
147e9034789SMichal Meloun .on_value = 0, \
148e9034789SMichal Meloun .off_value = 1, \
149e9034789SMichal Meloun }
150e9034789SMichal Meloun
151e9034789SMichal Meloun /* Fixed rate clock. */
152e9034789SMichal Meloun #define FRATE(_id, cname, _freq) \
153e9034789SMichal Meloun { \
154e9034789SMichal Meloun .clkdef.id = _id, \
155e9034789SMichal Meloun .clkdef.name = cname, \
156e9034789SMichal Meloun .clkdef.parent_names = NULL, \
157e9034789SMichal Meloun .clkdef.parent_cnt = 0, \
158e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
159e9034789SMichal Meloun .freq = _freq, \
160e9034789SMichal Meloun }
161e9034789SMichal Meloun
162e9034789SMichal Meloun /* Fixed rate multipier/divider. */
163e9034789SMichal Meloun #define FACT(_id, cname, pname, _mult, _div) \
164e9034789SMichal Meloun { \
165e9034789SMichal Meloun .clkdef.id = _id, \
166e9034789SMichal Meloun .clkdef.name = cname, \
167e9034789SMichal Meloun .clkdef.parent_names = (const char *[]){pname}, \
168e9034789SMichal Meloun .clkdef.parent_cnt = 1, \
169e9034789SMichal Meloun .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
170e9034789SMichal Meloun .mult = _mult, \
171e9034789SMichal Meloun .div = _div, \
172e9034789SMichal Meloun }
173e9034789SMichal Meloun
174e9034789SMichal Meloun static uint32_t osc_freqs[16] = {
175e9034789SMichal Meloun [0] = 13000000,
176e9034789SMichal Meloun [1] = 16800000,
177e9034789SMichal Meloun [4] = 19200000,
178e9034789SMichal Meloun [5] = 38400000,
179e9034789SMichal Meloun [8] = 12000000,
180e9034789SMichal Meloun [9] = 48000000,
181e9034789SMichal Meloun };
182e9034789SMichal Meloun
183e9034789SMichal Meloun
184e9034789SMichal Meloun /* Parent lists. */
185e9034789SMichal Meloun PLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60", "pc_xusb_ss" };
186e9034789SMichal Meloun PLIST(mux_xusb_ssp) = {"xusb_ss", "osc_div_clk"};
187e9034789SMichal Meloun
188e9034789SMichal Meloun
189b6724f70SGordon Bergling /* Clocks adjusted online. */
190e9034789SMichal Meloun static struct clk_fixed_def fixed_osc =
191e9034789SMichal Meloun FRATE(TEGRA210_CLK_CLK_M, "osc", 38400000);
192e9034789SMichal Meloun static struct clk_fixed_def fixed_clk_m =
193e9034789SMichal Meloun FACT(0, "clk_m", "osc", 1, 1);
194e9034789SMichal Meloun static struct clk_fixed_def fixed_osc_div =
195e9034789SMichal Meloun FACT(0, "osc_div_clk", "osc", 1, 1);
196e9034789SMichal Meloun
197e9034789SMichal Meloun static struct clk_fixed_def tegra210_fixed_clks[] = {
198e9034789SMichal Meloun /* Core clocks. */
199e9034789SMichal Meloun FRATE(0, "bogus", 1),
200e9034789SMichal Meloun FRATE(0, "clk_s", 32768),
201e9034789SMichal Meloun
202e9034789SMichal Meloun /* Audio clocks. */
203e9034789SMichal Meloun FRATE(0, "vimclk_sync", 1),
204e9034789SMichal Meloun FRATE(0, "i2s1_sync", 1),
205e9034789SMichal Meloun FRATE(0, "i2s2_sync", 1),
206e9034789SMichal Meloun FRATE(0, "i2s3_sync", 1),
207e9034789SMichal Meloun FRATE(0, "i2s4_sync", 1),
208e9034789SMichal Meloun FRATE(0, "i2s5_sync", 1),
209e9034789SMichal Meloun FRATE(0, "spdif_in_sync", 1),
210e9034789SMichal Meloun
211e9034789SMichal Meloun /* XUSB */
212e9034789SMichal Meloun FACT(TEGRA210_CLK_XUSB_SS_DIV2, "xusb_ss_div2", "xusb_ss", 1, 2),
213e9034789SMichal Meloun
214e9034789SMichal Meloun /* SOR */
215e9034789SMichal Meloun FACT(0, "sor_safe_div", "pllP_out0", 1, 17),
216e9034789SMichal Meloun FACT(0, "dpaux_div", "sor_safe", 1, 17),
217e9034789SMichal Meloun FACT(0, "dpaux1_div", "sor_safe", 1, 17),
218e9034789SMichal Meloun
219e9034789SMichal Meloun /* Not Yet Implemented */
220e9034789SMichal Meloun FRATE(0, "audio", 10000000),
221e9034789SMichal Meloun FRATE(0, "audio0", 10000000),
222e9034789SMichal Meloun FRATE(0, "audio1", 10000000),
223e9034789SMichal Meloun FRATE(0, "audio2", 10000000),
224e9034789SMichal Meloun FRATE(0, "audio3", 10000000),
225e9034789SMichal Meloun FRATE(0, "audio4", 10000000),
226e9034789SMichal Meloun FRATE(0, "ext_vimclk", 10000000),
227e9034789SMichal Meloun FRATE(0, "audiod1", 10000000),
228e9034789SMichal Meloun FRATE(0, "audiod2", 10000000),
229e9034789SMichal Meloun FRATE(0, "audiod3", 10000000),
230e9034789SMichal Meloun FRATE(0, "dfllCPU_out", 10000000),
231e9034789SMichal Meloun
232e9034789SMichal Meloun };
233e9034789SMichal Meloun
234e9034789SMichal Meloun
235e9034789SMichal Meloun static struct clk_mux_def tegra210_mux_clks[] = {
236e9034789SMichal Meloun /* USB. */
237e9034789SMichal Meloun MUX(TEGRA210_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 2),
238e9034789SMichal Meloun MUX(0, "xusb_ssp", mux_xusb_ssp, CLK_SOURCE_XUSB_SS, 24, 1),
239e9034789SMichal Meloun
240e9034789SMichal Meloun };
241e9034789SMichal Meloun
242e9034789SMichal Meloun
243e9034789SMichal Meloun static struct clk_gate_def tegra210_gate_clks[] = {
244e9034789SMichal Meloun /* Base peripheral clocks. */
245e9034789SMichal Meloun GATE_INV(TEGRA210_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7),
246e9034789SMichal Meloun GATE_INV(TEGRA210_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3),
247e9034789SMichal Meloun GATE(TEGRA210_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0),
248e9034789SMichal Meloun GATE(TEGRA210_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1),
249e9034789SMichal Meloun GATE(0, "pllD_dsi_csi", "pllD_out0", PLLD_MISC, 21),
250e9034789SMichal Meloun GATE(0, "pllP_hsio", "pllP_out0", PLLP_MISC1, 29),
251e9034789SMichal Meloun GATE(0, "pllP_xusb", "pllP_hsio", PLLP_MISC1, 28),
252e9034789SMichal Meloun };
253e9034789SMichal Meloun
254e9034789SMichal Meloun static struct clk_div_def tegra210_div_clks[] = {
255e9034789SMichal Meloun /* Base peripheral clocks. */
256e9034789SMichal Meloun DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0),
257e9034789SMichal Meloun DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0),
258e9034789SMichal Meloun };
259e9034789SMichal Meloun
260e9034789SMichal Meloun /* Initial setup table. */
261e9034789SMichal Meloun static struct tegra210_init_item clk_init_table[] = {
262e9034789SMichal Meloun /* clock, partent, frequency, enable */
263e9034789SMichal Meloun {"uarta", "pllP_out0", 408000000, 0},
264e9034789SMichal Meloun {"uartb", "pllP_out0", 408000000, 0},
265e9034789SMichal Meloun {"uartc", "pllP_out0", 408000000, 0},
266e9034789SMichal Meloun {"uartd", "pllP_out0", 408000000, 0},
267e9034789SMichal Meloun {"pllA", NULL, 564480000, 1},
268e9034789SMichal Meloun {"pllA_out0", NULL, 11289600, 1},
269e9034789SMichal Meloun {"extperiph1", "pllA_out0", 0, 1},
270e9034789SMichal Meloun {"i2s1", "pllA_out0", 11289600, 0},
271e9034789SMichal Meloun {"i2s2", "pllA_out0", 11289600, 0},
272e9034789SMichal Meloun {"i2s3", "pllA_out0", 11289600, 0},
273e9034789SMichal Meloun {"i2s4", "pllA_out0", 11289600, 0},
274e9034789SMichal Meloun {"i2s5", "pllA_out0", 11289600, 0},
275e9034789SMichal Meloun {"host1x", "pllP_out0", 136000000, 1},
276e9034789SMichal Meloun {"sclk", "pllP_out2", 102000000, 1},
277e9034789SMichal Meloun {"dvfs_soc", "pllP_out0", 51000000, 1},
278e9034789SMichal Meloun {"dvfs_ref", "pllP_out0", 51000000, 1},
279e9034789SMichal Meloun {"spi4", "pllP_out0", 12000000, 1},
280e9034789SMichal Meloun {"pllREFE", NULL, 672000000, 0},
281e9034789SMichal Meloun
282e9034789SMichal Meloun {"xusb", NULL, 0, 1},
283e9034789SMichal Meloun {"xusb_ss", "pllU_480", 120000000, 0},
284e9034789SMichal Meloun {"pc_xusb_fs", "pllU_48", 48000000, 0},
285e9034789SMichal Meloun {"xusb_hs", "pc_xusb_ss", 120000000, 0},
286e9034789SMichal Meloun {"xusb_ssp", "xusb_ss", 120000000, 0},
287e9034789SMichal Meloun {"pc_xusb_falcon", "pllP_xusb", 204000000, 0},
288e9034789SMichal Meloun {"pc_xusb_core_host", "pllP_xusb", 102000000, 0},
289e9034789SMichal Meloun {"pc_xusb_core_dev", "pllP_xusb", 102000000, 0},
290e9034789SMichal Meloun
291e9034789SMichal Meloun {"sata", "pllP_out0", 104000000, 0},
292e9034789SMichal Meloun {"sata_oob", "pllP_out0", 204000000, 0},
293e9034789SMichal Meloun {"emc", NULL, 0, 1},
294e9034789SMichal Meloun {"mselect", NULL, 0, 1},
295e9034789SMichal Meloun {"csite", NULL, 0, 1},
296e9034789SMichal Meloun
297e9034789SMichal Meloun {"dbgapb", NULL, 0, 1 },
298e9034789SMichal Meloun {"tsensor", "clk_m", 400000, 0},
299e9034789SMichal Meloun {"i2c1", "pllP_out0", 0, 0},
300e9034789SMichal Meloun {"i2c2", "pllP_out0", 0, 0},
301e9034789SMichal Meloun {"i2c3", "pllP_out0", 0, 0},
302e9034789SMichal Meloun {"i2c4", "pllP_out0", 0, 0},
303e9034789SMichal Meloun {"i2c5", "pllP_out0", 0, 0},
304e9034789SMichal Meloun {"i2c6", "pllP_out0", 0, 0},
305e9034789SMichal Meloun
306e9034789SMichal Meloun {"pllDP_out0", NULL, 270000000, 0},
307e9034789SMichal Meloun {"soc_therm", "pllP_out0", 51000000, 0},
308e9034789SMichal Meloun {"cclk_g", NULL, 0, 1},
309e9034789SMichal Meloun {"pllU_out1", NULL, 48000000, 1},
310e9034789SMichal Meloun {"pllU_out2", NULL, 60000000, 1},
311e9034789SMichal Meloun {"pllC4", NULL, 1000000000, 1},
312e9034789SMichal Meloun {"pllC4_out0", NULL, 1000000000, 1},
313e9034789SMichal Meloun };
314e9034789SMichal Meloun
315e9034789SMichal Meloun static void
init_divs(struct tegra210_car_softc * sc,struct clk_div_def * clks,int nclks)316e9034789SMichal Meloun init_divs(struct tegra210_car_softc *sc, struct clk_div_def *clks, int nclks)
317e9034789SMichal Meloun {
318e9034789SMichal Meloun int i, rv;
319e9034789SMichal Meloun
320e9034789SMichal Meloun for (i = 0; i < nclks; i++) {
321e9034789SMichal Meloun rv = clknode_div_register(sc->clkdom, clks + i);
322e9034789SMichal Meloun if (rv != 0)
323e9034789SMichal Meloun panic("clk_div_register failed");
324e9034789SMichal Meloun }
325e9034789SMichal Meloun }
326e9034789SMichal Meloun
327e9034789SMichal Meloun static void
init_gates(struct tegra210_car_softc * sc,struct clk_gate_def * clks,int nclks)328e9034789SMichal Meloun init_gates(struct tegra210_car_softc *sc, struct clk_gate_def *clks, int nclks)
329e9034789SMichal Meloun {
330e9034789SMichal Meloun int i, rv;
331e9034789SMichal Meloun
332e9034789SMichal Meloun
333e9034789SMichal Meloun for (i = 0; i < nclks; i++) {
334e9034789SMichal Meloun rv = clknode_gate_register(sc->clkdom, clks + i);
335e9034789SMichal Meloun if (rv != 0)
336e9034789SMichal Meloun panic("clk_gate_register failed");
337e9034789SMichal Meloun }
338e9034789SMichal Meloun }
339e9034789SMichal Meloun
340e9034789SMichal Meloun static void
init_muxes(struct tegra210_car_softc * sc,struct clk_mux_def * clks,int nclks)341e9034789SMichal Meloun init_muxes(struct tegra210_car_softc *sc, struct clk_mux_def *clks, int nclks)
342e9034789SMichal Meloun {
343e9034789SMichal Meloun int i, rv;
344e9034789SMichal Meloun
345e9034789SMichal Meloun
346e9034789SMichal Meloun for (i = 0; i < nclks; i++) {
347e9034789SMichal Meloun rv = clknode_mux_register(sc->clkdom, clks + i);
348e9034789SMichal Meloun if (rv != 0)
349e9034789SMichal Meloun panic("clk_mux_register failed");
350e9034789SMichal Meloun }
351e9034789SMichal Meloun }
352e9034789SMichal Meloun
353e9034789SMichal Meloun static void
init_fixeds(struct tegra210_car_softc * sc,struct clk_fixed_def * clks,int nclks)354e9034789SMichal Meloun init_fixeds(struct tegra210_car_softc *sc, struct clk_fixed_def *clks,
355e9034789SMichal Meloun int nclks)
356e9034789SMichal Meloun {
357e9034789SMichal Meloun int i, rv;
358e9034789SMichal Meloun uint32_t val;
359e9034789SMichal Meloun int osc_idx;
360e9034789SMichal Meloun
361e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, OSC_CTRL, &val);
362e9034789SMichal Meloun osc_idx = OSC_CTRL_OSC_FREQ_GET(val);
363e9034789SMichal Meloun fixed_osc.freq = osc_freqs[osc_idx];
364e9034789SMichal Meloun if (fixed_osc.freq == 0)
365e9034789SMichal Meloun panic("Undefined input frequency");
366e9034789SMichal Meloun rv = clknode_fixed_register(sc->clkdom, &fixed_osc);
367e9034789SMichal Meloun if (rv != 0)
368e9034789SMichal Meloun panic("clk_fixed_register failed");
369e9034789SMichal Meloun
370e9034789SMichal Meloun fixed_osc_div.div = 1 << OSC_CTRL_PLL_REF_DIV_GET(val);
371e9034789SMichal Meloun rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div);
372e9034789SMichal Meloun if (rv != 0)
373e9034789SMichal Meloun panic("clk_fixed_register failed");
374e9034789SMichal Meloun
375e9034789SMichal Meloun CLKDEV_READ_4(sc->dev, SPARE_REG0, &val);
376e9034789SMichal Meloun fixed_clk_m.div = SPARE_REG0_MDIV_GET(val) + 1;
377e9034789SMichal Meloun rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m);
378e9034789SMichal Meloun if (rv != 0)
379e9034789SMichal Meloun panic("clk_fixed_register failed");
380e9034789SMichal Meloun
381e9034789SMichal Meloun for (i = 0; i < nclks; i++) {
382e9034789SMichal Meloun rv = clknode_fixed_register(sc->clkdom, clks + i);
383e9034789SMichal Meloun if (rv != 0)
384e9034789SMichal Meloun panic("clk_fixed_register failed");
385e9034789SMichal Meloun }
386e9034789SMichal Meloun }
387e9034789SMichal Meloun
388e9034789SMichal Meloun static void
postinit_clock(struct tegra210_car_softc * sc)389e9034789SMichal Meloun postinit_clock(struct tegra210_car_softc *sc)
390e9034789SMichal Meloun {
391e9034789SMichal Meloun int i;
392e9034789SMichal Meloun struct tegra210_init_item *tbl;
393e9034789SMichal Meloun struct clknode *clknode;
394e9034789SMichal Meloun int rv;
395e9034789SMichal Meloun
396e9034789SMichal Meloun for (i = 0; i < nitems(clk_init_table); i++) {
397e9034789SMichal Meloun tbl = &clk_init_table[i];
398e9034789SMichal Meloun
399e9034789SMichal Meloun clknode = clknode_find_by_name(tbl->name);
400e9034789SMichal Meloun if (clknode == NULL) {
401e9034789SMichal Meloun device_printf(sc->dev, "Cannot find clock %s\n",
402e9034789SMichal Meloun tbl->name);
403e9034789SMichal Meloun continue;
404e9034789SMichal Meloun }
405e9034789SMichal Meloun if (tbl->parent != NULL) {
406e9034789SMichal Meloun rv = clknode_set_parent_by_name(clknode, tbl->parent);
407e9034789SMichal Meloun if (rv != 0) {
408e9034789SMichal Meloun device_printf(sc->dev,
409e9034789SMichal Meloun "Cannot set parent for %s (to %s): %d\n",
410e9034789SMichal Meloun tbl->name, tbl->parent, rv);
411e9034789SMichal Meloun continue;
412e9034789SMichal Meloun }
413e9034789SMichal Meloun }
414e9034789SMichal Meloun if (tbl->frequency != 0) {
415e9034789SMichal Meloun rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999);
416e9034789SMichal Meloun if (rv != 0) {
417e9034789SMichal Meloun device_printf(sc->dev,
418e9034789SMichal Meloun "Cannot set frequency for %s: %d\n",
419e9034789SMichal Meloun tbl->name, rv);
420e9034789SMichal Meloun continue;
421e9034789SMichal Meloun }
422e9034789SMichal Meloun }
423e9034789SMichal Meloun if (tbl->enable!= 0) {
424e9034789SMichal Meloun rv = clknode_enable(clknode);
425e9034789SMichal Meloun if (rv != 0) {
426e9034789SMichal Meloun device_printf(sc->dev,
427e9034789SMichal Meloun "Cannot enable %s: %d\n", tbl->name, rv);
428e9034789SMichal Meloun continue;
429e9034789SMichal Meloun }
430e9034789SMichal Meloun }
431e9034789SMichal Meloun }
432e9034789SMichal Meloun }
433e9034789SMichal Meloun
434e9034789SMichal Meloun static void
register_clocks(device_t dev)435e9034789SMichal Meloun register_clocks(device_t dev)
436e9034789SMichal Meloun {
437e9034789SMichal Meloun struct tegra210_car_softc *sc;
438e9034789SMichal Meloun
439e9034789SMichal Meloun sc = device_get_softc(dev);
440e9034789SMichal Meloun sc->clkdom = clkdom_create(dev);
441e9034789SMichal Meloun if (sc->clkdom == NULL)
442e9034789SMichal Meloun panic("clkdom == NULL");
443e9034789SMichal Meloun
444e9034789SMichal Meloun init_fixeds(sc, tegra210_fixed_clks, nitems(tegra210_fixed_clks));
445e9034789SMichal Meloun tegra210_init_plls(sc);
446e9034789SMichal Meloun init_muxes(sc, tegra210_mux_clks, nitems(tegra210_mux_clks));
447e9034789SMichal Meloun init_divs(sc, tegra210_div_clks, nitems(tegra210_div_clks));
448e9034789SMichal Meloun init_gates(sc, tegra210_gate_clks, nitems(tegra210_gate_clks));
449e9034789SMichal Meloun tegra210_periph_clock(sc);
450e9034789SMichal Meloun tegra210_super_mux_clock(sc);
451e9034789SMichal Meloun clkdom_finit(sc->clkdom);
452e9034789SMichal Meloun clkdom_xlock(sc->clkdom);
453e9034789SMichal Meloun postinit_clock(sc);
454e9034789SMichal Meloun clkdom_unlock(sc->clkdom);
455e9034789SMichal Meloun if (bootverbose)
456e9034789SMichal Meloun clkdom_dump(sc->clkdom);
457e9034789SMichal Meloun }
458e9034789SMichal Meloun
459e9034789SMichal Meloun static int
tegra210_car_clkdev_read_4(device_t dev,bus_addr_t addr,uint32_t * val)460e9034789SMichal Meloun tegra210_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
461e9034789SMichal Meloun {
462e9034789SMichal Meloun struct tegra210_car_softc *sc;
463e9034789SMichal Meloun
464e9034789SMichal Meloun sc = device_get_softc(dev);
465e9034789SMichal Meloun *val = bus_read_4(sc->mem_res, addr);
466e9034789SMichal Meloun return (0);
467e9034789SMichal Meloun }
468e9034789SMichal Meloun
469e9034789SMichal Meloun static int
tegra210_car_clkdev_write_4(device_t dev,bus_addr_t addr,uint32_t val)470e9034789SMichal Meloun tegra210_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val)
471e9034789SMichal Meloun {
472e9034789SMichal Meloun struct tegra210_car_softc *sc;
473e9034789SMichal Meloun
474e9034789SMichal Meloun sc = device_get_softc(dev);
475e9034789SMichal Meloun bus_write_4(sc->mem_res, addr, val);
476e9034789SMichal Meloun return (0);
477e9034789SMichal Meloun }
478e9034789SMichal Meloun
479e9034789SMichal Meloun static int
tegra210_car_clkdev_modify_4(device_t dev,bus_addr_t addr,uint32_t clear_mask,uint32_t set_mask)480e9034789SMichal Meloun tegra210_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask,
481e9034789SMichal Meloun uint32_t set_mask)
482e9034789SMichal Meloun {
483e9034789SMichal Meloun struct tegra210_car_softc *sc;
484e9034789SMichal Meloun uint32_t reg;
485e9034789SMichal Meloun
486e9034789SMichal Meloun sc = device_get_softc(dev);
487e9034789SMichal Meloun reg = bus_read_4(sc->mem_res, addr);
488e9034789SMichal Meloun reg &= ~clear_mask;
489e9034789SMichal Meloun reg |= set_mask;
490e9034789SMichal Meloun bus_write_4(sc->mem_res, addr, reg);
491e9034789SMichal Meloun return (0);
492e9034789SMichal Meloun }
493e9034789SMichal Meloun
494e9034789SMichal Meloun static void
tegra210_car_clkdev_device_lock(device_t dev)495e9034789SMichal Meloun tegra210_car_clkdev_device_lock(device_t dev)
496e9034789SMichal Meloun {
497e9034789SMichal Meloun struct tegra210_car_softc *sc;
498e9034789SMichal Meloun
499e9034789SMichal Meloun sc = device_get_softc(dev);
500e9034789SMichal Meloun mtx_lock(&sc->mtx);
501e9034789SMichal Meloun }
502e9034789SMichal Meloun
503e9034789SMichal Meloun static void
tegra210_car_clkdev_device_unlock(device_t dev)504e9034789SMichal Meloun tegra210_car_clkdev_device_unlock(device_t dev)
505e9034789SMichal Meloun {
506e9034789SMichal Meloun struct tegra210_car_softc *sc;
507e9034789SMichal Meloun
508e9034789SMichal Meloun sc = device_get_softc(dev);
509e9034789SMichal Meloun mtx_unlock(&sc->mtx);
510e9034789SMichal Meloun }
511e9034789SMichal Meloun
512e9034789SMichal Meloun static int
tegra210_car_detach(device_t dev)513e9034789SMichal Meloun tegra210_car_detach(device_t dev)
514e9034789SMichal Meloun {
515e9034789SMichal Meloun
516e9034789SMichal Meloun device_printf(dev, "Error: Clock driver cannot be detached\n");
517e9034789SMichal Meloun return (EBUSY);
518e9034789SMichal Meloun }
519e9034789SMichal Meloun
520e9034789SMichal Meloun static int
tegra210_car_probe(device_t dev)521e9034789SMichal Meloun tegra210_car_probe(device_t dev)
522e9034789SMichal Meloun {
523e9034789SMichal Meloun
524e9034789SMichal Meloun if (!ofw_bus_status_okay(dev))
525e9034789SMichal Meloun return (ENXIO);
526e9034789SMichal Meloun
527e9034789SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
528e9034789SMichal Meloun device_set_desc(dev, "Tegra Clock Driver");
529e9034789SMichal Meloun return (BUS_PROBE_DEFAULT);
530e9034789SMichal Meloun }
531e9034789SMichal Meloun
532e9034789SMichal Meloun return (ENXIO);
533e9034789SMichal Meloun }
534e9034789SMichal Meloun
535e9034789SMichal Meloun static int
tegra210_car_attach(device_t dev)536e9034789SMichal Meloun tegra210_car_attach(device_t dev)
537e9034789SMichal Meloun {
538e9034789SMichal Meloun struct tegra210_car_softc *sc = device_get_softc(dev);
539e9034789SMichal Meloun int rid, rv;
540e9034789SMichal Meloun
541e9034789SMichal Meloun sc->dev = dev;
542e9034789SMichal Meloun
543e9034789SMichal Meloun mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
544e9034789SMichal Meloun sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
545e9034789SMichal Meloun
546e9034789SMichal Meloun /* Resource setup. */
547e9034789SMichal Meloun rid = 0;
548e9034789SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
549e9034789SMichal Meloun RF_ACTIVE);
550e9034789SMichal Meloun if (!sc->mem_res) {
551e9034789SMichal Meloun device_printf(dev, "cannot allocate memory resource\n");
552e9034789SMichal Meloun rv = ENXIO;
553e9034789SMichal Meloun goto fail;
554e9034789SMichal Meloun }
555e9034789SMichal Meloun
556e9034789SMichal Meloun register_clocks(dev);
557e9034789SMichal Meloun hwreset_register_ofw_provider(dev);
558e9034789SMichal Meloun return (0);
559e9034789SMichal Meloun
560e9034789SMichal Meloun fail:
561e9034789SMichal Meloun if (sc->mem_res)
562e9034789SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
563e9034789SMichal Meloun
564e9034789SMichal Meloun return (rv);
565e9034789SMichal Meloun }
566e9034789SMichal Meloun
567e9034789SMichal Meloun static int
tegra210_car_hwreset_assert(device_t dev,intptr_t id,bool value)568e9034789SMichal Meloun tegra210_car_hwreset_assert(device_t dev, intptr_t id, bool value)
569e9034789SMichal Meloun {
570e9034789SMichal Meloun struct tegra210_car_softc *sc = device_get_softc(dev);
571e9034789SMichal Meloun
572e9034789SMichal Meloun return (tegra210_hwreset_by_idx(sc, id, value));
573e9034789SMichal Meloun }
574e9034789SMichal Meloun
575e9034789SMichal Meloun static device_method_t tegra210_car_methods[] = {
576e9034789SMichal Meloun /* Device interface */
577e9034789SMichal Meloun DEVMETHOD(device_probe, tegra210_car_probe),
578e9034789SMichal Meloun DEVMETHOD(device_attach, tegra210_car_attach),
579e9034789SMichal Meloun DEVMETHOD(device_detach, tegra210_car_detach),
580e9034789SMichal Meloun
581e9034789SMichal Meloun /* Clkdev interface*/
582e9034789SMichal Meloun DEVMETHOD(clkdev_read_4, tegra210_car_clkdev_read_4),
583e9034789SMichal Meloun DEVMETHOD(clkdev_write_4, tegra210_car_clkdev_write_4),
584e9034789SMichal Meloun DEVMETHOD(clkdev_modify_4, tegra210_car_clkdev_modify_4),
585e9034789SMichal Meloun DEVMETHOD(clkdev_device_lock, tegra210_car_clkdev_device_lock),
586e9034789SMichal Meloun DEVMETHOD(clkdev_device_unlock, tegra210_car_clkdev_device_unlock),
587e9034789SMichal Meloun
588e9034789SMichal Meloun /* Reset interface */
589e9034789SMichal Meloun DEVMETHOD(hwreset_assert, tegra210_car_hwreset_assert),
590e9034789SMichal Meloun
591e9034789SMichal Meloun DEVMETHOD_END
592e9034789SMichal Meloun };
593e9034789SMichal Meloun
594e9034789SMichal Meloun static DEFINE_CLASS_0(car, tegra210_car_driver, tegra210_car_methods,
595e9034789SMichal Meloun sizeof(struct tegra210_car_softc));
596289f133bSJohn Baldwin EARLY_DRIVER_MODULE(tegra210_car, simplebus, tegra210_car_driver, NULL, NULL,
597289f133bSJohn Baldwin BUS_PASS_TIMER);
598