]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/nvidia/tegra210/tegra210_clk_super.c
libarchive: merge from vendor branch
[FreeBSD/FreeBSD.git] / sys / arm64 / nvidia / tegra210 / tegra210_clk_super.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/rman.h>
37
38 #include <machine/bus.h>
39
40 #include <dev/extres/clk/clk.h>
41
42 #include <dt-bindings/clock/tegra210-car.h>
43 #include "tegra210_car.h"
44
45 struct super_mux_def {
46         struct clknode_init_def clkdef;
47         uint32_t                base_reg;
48         uint32_t                flags;
49 };
50
51 #define PLIST(x) static const char *x[]
52 #define SM(_id, cn, pl, r)                                              \
53 {                                                                       \
54         .clkdef.id = _id,                                               \
55         .clkdef.name = cn,                                              \
56         .clkdef.parent_names = pl,                                      \
57         .clkdef.parent_cnt = nitems(pl),                                \
58         .clkdef.flags = CLK_NODE_STATIC_STRINGS,                        \
59         .base_reg = r,                                                  \
60 }
61
62
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",
68 };
69
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",
75 };
76
77 PLIST(sclk_parents) = {
78         "clk_m", "pllC_out1", "pllC4_out3", "pllP_out0",
79         "pllP_out2", "pllC4_out1", "clk_s", "pllC4_out1",
80 };
81
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),
86 };
87
88 static int super_mux_init(struct clknode *clk, device_t dev);
89 static int super_mux_set_mux(struct clknode *clk, int idx);
90
91 struct super_mux_sc {
92         device_t                clkdev;
93         uint32_t                base_reg;
94         uint32_t                flags;
95
96         int                     mux;
97 };
98
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),
103         CLKNODEMETHOD_END
104 };
105 DEFINE_CLASS_1(tegra210_super_mux, tegra210_super_mux_class, super_mux_methods,
106    sizeof(struct super_mux_sc), clknode_class);
107
108 /* Mux status. */
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
114
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
124
125 #define SUPER_MUX_MUX_WIDTH             4
126
127 static uint32_t
128 super_mux_get_state(uint32_t reg)
129 {
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);
140 }
141
142 static int
143 super_mux_init(struct clknode *clk, device_t dev)
144 {
145         struct super_mux_sc *sc;
146         uint32_t reg;
147         int shift, state;
148
149         sc = clknode_get_softc(clk);
150
151         DEVICE_LOCK(sc);
152         RD4(sc, sc->base_reg, &reg);
153         DEVICE_UNLOCK(sc);
154         state = super_mux_get_state(reg);
155
156         if ((state != SUPER_MUX_STATE_RUN) &&
157             (state != SUPER_MUX_STATE_IDLE)) {
158                 panic("Unexpected super mux state: %u", state);
159         }
160
161         shift = state * SUPER_MUX_MUX_WIDTH;
162         sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);
163
164         clknode_init_parent_idx(clk, sc->mux);
165
166         return(0);
167 }
168
169 static int
170 super_mux_set_mux(struct clknode *clk, int idx)
171 {
172
173         struct super_mux_sc *sc;
174         int shift, state;
175         uint32_t reg, dummy;
176
177         sc = clknode_get_softc(clk);
178
179         DEVICE_LOCK(sc);
180         RD4(sc, sc->base_reg, &reg);
181         state = super_mux_get_state(reg);
182
183         if ((state != SUPER_MUX_STATE_RUN) &&
184             (state != SUPER_MUX_STATE_IDLE)) {
185                 panic("Unexpected super mux state: %u", state);
186         }
187
188         shift = (state - 1) * SUPER_MUX_MUX_WIDTH;
189         sc->mux = idx;
190         reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
191         reg |= idx << shift;
192
193         WR4(sc, sc->base_reg, reg);
194         RD4(sc, sc->base_reg, &dummy);
195         DEVICE_UNLOCK(sc);
196
197         return(0);
198 }
199
200 static int
201 super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)
202 {
203         struct clknode *clk;
204         struct super_mux_sc *sc;
205
206         clk = clknode_create(clkdom, &tegra210_super_mux_class,
207             &clkdef->clkdef);
208         if (clk == NULL)
209                 return (1);
210
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;
215
216         clknode_register(clkdom, clk);
217         return (0);
218 }
219
220 void
221 tegra210_super_mux_clock(struct tegra210_car_softc *sc)
222 {
223         int i, rv;
224
225         for (i = 0; i <  nitems(super_mux_def); i++) {
226                 rv = super_mux_register(sc->clkdom, &super_mux_def[i]);
227                 if (rv != 0)
228                         panic("super_mux_register failed");
229         }
230
231 }