2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
35 #include <sys/mutex.h>
38 #include <machine/bus.h>
40 #include <dev/extres/clk/clk.h>
42 #include <dt-bindings/clock/tegra210-car.h>
43 #include "tegra210_car.h"
45 struct super_mux_def {
46 struct clknode_init_def clkdef;
51 #define PLIST(x) static const char *x[]
52 #define SM(_id, cn, pl, r) \
56 .clkdef.parent_names = pl, \
57 .clkdef.parent_cnt = nitems(pl), \
58 .clkdef.flags = CLK_NODE_STATIC_STRINGS, \
63 PLIST(cclk_g_parents) = {
64 "clk_m", NULL, "clk_s", NULL,
65 "pllP_out0", "pllP_out4", NULL, NULL,
66 "pllX_out0", "dfllCPU_out_alias", NULL, NULL,
67 NULL, NULL, "pllX_out0_alias", "dfllCPU_out",
70 PLIST(cclk_lp_parents) = {
71 "clk_m", NULL, "clk_s", NULL,
72 "pllP_out0", "pllP_out4", NULL, NULL,
73 "pllX_out0", "dfllCPU_out_alias", NULL, NULL,
74 NULL, NULL, "pllX_out0_alias", "dfllCPU_out",
77 PLIST(sclk_parents) = {
78 "clk_m", "pllC_out1", "pllC4_out3", "pllP_out0",
79 "pllP_out2", "pllC4_out1", "clk_s", "pllC4_out1",
82 static struct super_mux_def super_mux_def[] = {
83 SM(TEGRA210_CLK_CCLK_G, "cclk_g", cclk_g_parents, CCLKG_BURST_POLICY),
84 SM(TEGRA210_CLK_CCLK_LP, "cclk_lp", cclk_lp_parents, CCLKLP_BURST_POLICY),
85 SM(TEGRA210_CLK_SCLK, "sclk", sclk_parents, SCLK_BURST_POLICY),
88 static int super_mux_init(struct clknode *clk, device_t dev);
89 static int super_mux_set_mux(struct clknode *clk, int idx);
99 static clknode_method_t super_mux_methods[] = {
100 /* Device interface */
101 CLKNODEMETHOD(clknode_init, super_mux_init),
102 CLKNODEMETHOD(clknode_set_mux, super_mux_set_mux),
105 DEFINE_CLASS_1(tegra210_super_mux, tegra210_super_mux_class, super_mux_methods,
106 sizeof(struct super_mux_sc), clknode_class);
109 #define SUPER_MUX_STATE_STDBY 0
110 #define SUPER_MUX_STATE_IDLE 1
111 #define SUPER_MUX_STATE_RUN 2
112 #define SUPER_MUX_STATE_IRQ 3
113 #define SUPER_MUX_STATE_FIQ 4
115 /* Mux register bits. */
116 #define SUPER_MUX_STATE_BIT_SHIFT 28
117 #define SUPER_MUX_STATE_BIT_MASK 0xF
118 /* State is Priority encoded */
119 #define SUPER_MUX_STATE_BIT_STDBY 0x00
120 #define SUPER_MUX_STATE_BIT_IDLE 0x01
121 #define SUPER_MUX_STATE_BIT_RUN 0x02
122 #define SUPER_MUX_STATE_BIT_IRQ 0x04
123 #define SUPER_MUX_STATE_BIT_FIQ 0x08
125 #define SUPER_MUX_MUX_WIDTH 4
128 super_mux_get_state(uint32_t reg)
130 reg = (reg >> SUPER_MUX_STATE_BIT_SHIFT) & SUPER_MUX_STATE_BIT_MASK;
131 if (reg & SUPER_MUX_STATE_BIT_FIQ)
132 return (SUPER_MUX_STATE_FIQ);
133 if (reg & SUPER_MUX_STATE_BIT_IRQ)
134 return (SUPER_MUX_STATE_IRQ);
135 if (reg & SUPER_MUX_STATE_BIT_RUN)
136 return (SUPER_MUX_STATE_RUN);
137 if (reg & SUPER_MUX_STATE_BIT_IDLE)
138 return (SUPER_MUX_STATE_IDLE);
139 return (SUPER_MUX_STATE_STDBY);
143 super_mux_init(struct clknode *clk, device_t dev)
145 struct super_mux_sc *sc;
149 sc = clknode_get_softc(clk);
152 RD4(sc, sc->base_reg, ®);
154 state = super_mux_get_state(reg);
156 if ((state != SUPER_MUX_STATE_RUN) &&
157 (state != SUPER_MUX_STATE_IDLE)) {
158 panic("Unexpected super mux state: %u", state);
161 shift = state * SUPER_MUX_MUX_WIDTH;
162 sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);
164 clknode_init_parent_idx(clk, sc->mux);
170 super_mux_set_mux(struct clknode *clk, int idx)
173 struct super_mux_sc *sc;
177 sc = clknode_get_softc(clk);
180 RD4(sc, sc->base_reg, ®);
181 state = super_mux_get_state(reg);
183 if ((state != SUPER_MUX_STATE_RUN) &&
184 (state != SUPER_MUX_STATE_IDLE)) {
185 panic("Unexpected super mux state: %u", state);
188 shift = (state - 1) * SUPER_MUX_MUX_WIDTH;
190 reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
193 WR4(sc, sc->base_reg, reg);
194 RD4(sc, sc->base_reg, &dummy);
201 super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)
204 struct super_mux_sc *sc;
206 clk = clknode_create(clkdom, &tegra210_super_mux_class,
211 sc = clknode_get_softc(clk);
212 sc->clkdev = clknode_get_device(clk);
213 sc->base_reg = clkdef->base_reg;
214 sc->flags = clkdef->flags;
216 clknode_register(clkdom, clk);
221 tegra210_super_mux_clock(struct tegra210_car_softc *sc)
225 for (i = 0; i < nitems(super_mux_def); i++) {
226 rv = super_mux_register(sc->clkdom, &super_mux_def[i]);
228 panic("super_mux_register failed");