Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/nvidia/tegra210/tegra210_clk_super.c
48266 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright 2020 Michal Meloun <[email protected]>
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/param.h>
29
#include <sys/systm.h>
30
#include <sys/bus.h>
31
#include <sys/lock.h>
32
#include <sys/mutex.h>
33
#include <sys/rman.h>
34
35
#include <machine/bus.h>
36
37
#include <dev/clk/clk.h>
38
39
#include <dt-bindings/clock/tegra210-car.h>
40
#include "tegra210_car.h"
41
42
struct super_mux_def {
43
struct clknode_init_def clkdef;
44
uint32_t base_reg;
45
uint32_t flags;
46
};
47
48
#define PLIST(x) static const char *x[]
49
#define SM(_id, cn, pl, r) \
50
{ \
51
.clkdef.id = _id, \
52
.clkdef.name = cn, \
53
.clkdef.parent_names = pl, \
54
.clkdef.parent_cnt = nitems(pl), \
55
.clkdef.flags = CLK_NODE_STATIC_STRINGS, \
56
.base_reg = r, \
57
}
58
59
60
PLIST(cclk_g_parents) = {
61
"clk_m", NULL, "clk_s", NULL,
62
"pllP_out0", "pllP_out4", NULL, NULL,
63
"pllX_out0", "dfllCPU_out_alias", NULL, NULL,
64
NULL, NULL, "pllX_out0_alias", "dfllCPU_out",
65
};
66
67
PLIST(cclk_lp_parents) = {
68
"clk_m", NULL, "clk_s", NULL,
69
"pllP_out0", "pllP_out4", NULL, NULL,
70
"pllX_out0", "dfllCPU_out_alias", NULL, NULL,
71
NULL, NULL, "pllX_out0_alias", "dfllCPU_out",
72
};
73
74
PLIST(sclk_parents) = {
75
"clk_m", "pllC_out1", "pllC4_out3", "pllP_out0",
76
"pllP_out2", "pllC4_out1", "clk_s", "pllC4_out1",
77
};
78
79
static struct super_mux_def super_mux_def[] = {
80
SM(TEGRA210_CLK_CCLK_G, "cclk_g", cclk_g_parents, CCLKG_BURST_POLICY),
81
SM(TEGRA210_CLK_CCLK_LP, "cclk_lp", cclk_lp_parents, CCLKLP_BURST_POLICY),
82
SM(TEGRA210_CLK_SCLK, "sclk", sclk_parents, SCLK_BURST_POLICY),
83
};
84
85
static int super_mux_init(struct clknode *clk, device_t dev);
86
static int super_mux_set_mux(struct clknode *clk, int idx);
87
88
struct super_mux_sc {
89
device_t clkdev;
90
uint32_t base_reg;
91
uint32_t flags;
92
93
int mux;
94
};
95
96
static clknode_method_t super_mux_methods[] = {
97
/* Device interface */
98
CLKNODEMETHOD(clknode_init, super_mux_init),
99
CLKNODEMETHOD(clknode_set_mux, super_mux_set_mux),
100
CLKNODEMETHOD_END
101
};
102
DEFINE_CLASS_1(tegra210_super_mux, tegra210_super_mux_class, super_mux_methods,
103
sizeof(struct super_mux_sc), clknode_class);
104
105
/* Mux status. */
106
#define SUPER_MUX_STATE_STDBY 0
107
#define SUPER_MUX_STATE_IDLE 1
108
#define SUPER_MUX_STATE_RUN 2
109
#define SUPER_MUX_STATE_IRQ 3
110
#define SUPER_MUX_STATE_FIQ 4
111
112
/* Mux register bits. */
113
#define SUPER_MUX_STATE_BIT_SHIFT 28
114
#define SUPER_MUX_STATE_BIT_MASK 0xF
115
/* State is Priority encoded */
116
#define SUPER_MUX_STATE_BIT_STDBY 0x00
117
#define SUPER_MUX_STATE_BIT_IDLE 0x01
118
#define SUPER_MUX_STATE_BIT_RUN 0x02
119
#define SUPER_MUX_STATE_BIT_IRQ 0x04
120
#define SUPER_MUX_STATE_BIT_FIQ 0x08
121
122
#define SUPER_MUX_MUX_WIDTH 4
123
124
static uint32_t
125
super_mux_get_state(uint32_t reg)
126
{
127
reg = (reg >> SUPER_MUX_STATE_BIT_SHIFT) & SUPER_MUX_STATE_BIT_MASK;
128
if (reg & SUPER_MUX_STATE_BIT_FIQ)
129
return (SUPER_MUX_STATE_FIQ);
130
if (reg & SUPER_MUX_STATE_BIT_IRQ)
131
return (SUPER_MUX_STATE_IRQ);
132
if (reg & SUPER_MUX_STATE_BIT_RUN)
133
return (SUPER_MUX_STATE_RUN);
134
if (reg & SUPER_MUX_STATE_BIT_IDLE)
135
return (SUPER_MUX_STATE_IDLE);
136
return (SUPER_MUX_STATE_STDBY);
137
}
138
139
static int
140
super_mux_init(struct clknode *clk, device_t dev)
141
{
142
struct super_mux_sc *sc;
143
uint32_t reg;
144
int shift, state;
145
146
sc = clknode_get_softc(clk);
147
148
DEVICE_LOCK(sc);
149
RD4(sc, sc->base_reg, &reg);
150
DEVICE_UNLOCK(sc);
151
state = super_mux_get_state(reg);
152
153
if ((state != SUPER_MUX_STATE_RUN) &&
154
(state != SUPER_MUX_STATE_IDLE)) {
155
panic("Unexpected super mux state: %u", state);
156
}
157
158
shift = state * SUPER_MUX_MUX_WIDTH;
159
sc->mux = (reg >> shift) & ((1 << SUPER_MUX_MUX_WIDTH) - 1);
160
161
clknode_init_parent_idx(clk, sc->mux);
162
163
return(0);
164
}
165
166
static int
167
super_mux_set_mux(struct clknode *clk, int idx)
168
{
169
170
struct super_mux_sc *sc;
171
int shift, state;
172
uint32_t reg, dummy;
173
174
sc = clknode_get_softc(clk);
175
176
DEVICE_LOCK(sc);
177
RD4(sc, sc->base_reg, &reg);
178
state = super_mux_get_state(reg);
179
180
if ((state != SUPER_MUX_STATE_RUN) &&
181
(state != SUPER_MUX_STATE_IDLE)) {
182
panic("Unexpected super mux state: %u", state);
183
}
184
185
shift = (state - 1) * SUPER_MUX_MUX_WIDTH;
186
sc->mux = idx;
187
reg &= ~(((1 << SUPER_MUX_MUX_WIDTH) - 1) << shift);
188
reg |= idx << shift;
189
190
WR4(sc, sc->base_reg, reg);
191
RD4(sc, sc->base_reg, &dummy);
192
DEVICE_UNLOCK(sc);
193
194
return(0);
195
}
196
197
static int
198
super_mux_register(struct clkdom *clkdom, struct super_mux_def *clkdef)
199
{
200
struct clknode *clk;
201
struct super_mux_sc *sc;
202
203
clk = clknode_create(clkdom, &tegra210_super_mux_class,
204
&clkdef->clkdef);
205
if (clk == NULL)
206
return (1);
207
208
sc = clknode_get_softc(clk);
209
sc->clkdev = clknode_get_device(clk);
210
sc->base_reg = clkdef->base_reg;
211
sc->flags = clkdef->flags;
212
213
clknode_register(clkdom, clk);
214
return (0);
215
}
216
217
void
218
tegra210_super_mux_clock(struct tegra210_car_softc *sc)
219
{
220
int i, rv;
221
222
for (i = 0; i < nitems(super_mux_def); i++) {
223
rv = super_mux_register(sc->clkdom, &super_mux_def[i]);
224
if (rv != 0)
225
panic("super_mux_register failed");
226
}
227
228
}
229
230