Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/clk/rockchip/rk_cru.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2018 Emmanuel Vadot <[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 ``AS IS'' AND ANY EXPRESS OR
16
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
* 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
/*
29
* RockChip Clock and Reset Unit
30
*/
31
32
#include <sys/param.h>
33
#include <sys/systm.h>
34
#include <sys/bus.h>
35
#include <sys/rman.h>
36
#include <sys/kernel.h>
37
#include <sys/lock.h>
38
#include <sys/module.h>
39
#include <sys/mutex.h>
40
#include <machine/bus.h>
41
42
#include <dev/fdt/simplebus.h>
43
44
#include <dev/ofw/ofw_bus.h>
45
#include <dev/ofw/ofw_bus_subr.h>
46
47
#include <dev/clk/clk.h>
48
#include <dev/clk/clk_gate.h>
49
#include <dev/clk/clk_fixed.h>
50
#include <dev/clk/clk_link.h>
51
#include <dev/hwreset/hwreset.h>
52
53
#include <dev/clk/rockchip/rk_clk_composite.h>
54
#include <dev/clk/rockchip/rk_clk_gate.h>
55
#include <dev/clk/rockchip/rk_clk_mux.h>
56
#include <dev/clk/rockchip/rk_clk_pll.h>
57
#include <dev/clk/rockchip/rk_cru.h>
58
59
#include "clkdev_if.h"
60
#include "hwreset_if.h"
61
62
static struct resource_spec rk_cru_spec[] = {
63
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
64
{ -1, 0 }
65
};
66
67
#define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg))
68
#define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
69
70
void rk3328_cru_register_clocks(struct rk_cru_softc *sc);
71
72
static int
73
rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
74
{
75
struct rk_cru_softc *sc;
76
77
sc = device_get_softc(dev);
78
CCU_WRITE4(sc, addr, val);
79
return (0);
80
}
81
82
static int
83
rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
84
{
85
struct rk_cru_softc *sc;
86
87
sc = device_get_softc(dev);
88
89
*val = CCU_READ4(sc, addr);
90
return (0);
91
}
92
93
static int
94
rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
95
{
96
struct rk_cru_softc *sc;
97
uint32_t reg;
98
99
sc = device_get_softc(dev);
100
101
reg = CCU_READ4(sc, addr);
102
reg &= ~clr;
103
reg |= set;
104
CCU_WRITE4(sc, addr, reg);
105
106
return (0);
107
}
108
109
static int
110
rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
111
{
112
struct rk_cru_softc *sc;
113
uint32_t reg;
114
int bit;
115
uint32_t val;
116
117
sc = device_get_softc(dev);
118
119
if (id > sc->reset_num)
120
return (ENXIO);
121
122
reg = sc->reset_offset + id / 16 * 4;
123
bit = id % 16;
124
125
mtx_lock(&sc->mtx);
126
val = 0;
127
if (reset)
128
val = (1 << bit);
129
CCU_WRITE4(sc, reg, val | ((1 << bit) << 16));
130
mtx_unlock(&sc->mtx);
131
132
return (0);
133
}
134
135
static int
136
rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
137
{
138
struct rk_cru_softc *sc;
139
uint32_t reg;
140
int bit;
141
uint32_t val;
142
143
sc = device_get_softc(dev);
144
145
if (id > sc->reset_num)
146
return (ENXIO);
147
reg = sc->reset_offset + id / 16 * 4;
148
bit = id % 16;
149
150
mtx_lock(&sc->mtx);
151
val = CCU_READ4(sc, reg);
152
mtx_unlock(&sc->mtx);
153
154
*reset = false;
155
if (val & (1 << bit))
156
*reset = true;
157
158
return (0);
159
}
160
161
static void
162
rk_cru_device_lock(device_t dev)
163
{
164
struct rk_cru_softc *sc;
165
166
sc = device_get_softc(dev);
167
mtx_lock(&sc->mtx);
168
}
169
170
static void
171
rk_cru_device_unlock(device_t dev)
172
{
173
struct rk_cru_softc *sc;
174
175
sc = device_get_softc(dev);
176
mtx_unlock(&sc->mtx);
177
}
178
179
static int
180
rk_cru_register_gates(struct rk_cru_softc *sc)
181
{
182
struct rk_clk_gate_def def;
183
int i;
184
185
for (i = 0; i < sc->ngates; i++) {
186
if (sc->gates[i].name == NULL)
187
continue;
188
memset(&def, 0, sizeof(def));
189
def.clkdef.id = sc->gates[i].id;
190
def.clkdef.name = sc->gates[i].name;
191
def.clkdef.parent_names = &sc->gates[i].parent_name;
192
def.clkdef.parent_cnt = 1;
193
def.offset = sc->gates[i].offset;
194
def.shift = sc->gates[i].shift;
195
def.mask = 1;
196
def.on_value = 0;
197
def.off_value = 1;
198
rk_clk_gate_register(sc->clkdom, &def);
199
}
200
201
return (0);
202
}
203
204
int
205
rk_cru_attach(device_t dev)
206
{
207
struct rk_cru_softc *sc;
208
phandle_t node;
209
int i;
210
211
sc = device_get_softc(dev);
212
sc->dev = dev;
213
214
node = ofw_bus_get_node(dev);
215
216
if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
217
device_printf(dev, "cannot allocate resources for device\n");
218
return (ENXIO);
219
}
220
221
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
222
223
sc->clkdom = clkdom_create(dev);
224
if (sc->clkdom == NULL)
225
panic("Cannot create clkdom\n");
226
227
for (i = 0; i < sc->nclks; i++) {
228
switch (sc->clks[i].type) {
229
case RK_CLK_UNDEFINED:
230
break;
231
case RK3066_CLK_PLL:
232
rk3066_clk_pll_register(sc->clkdom,
233
sc->clks[i].clk.pll);
234
break;
235
case RK3328_CLK_PLL:
236
rk3328_clk_pll_register(sc->clkdom,
237
sc->clks[i].clk.pll);
238
break;
239
case RK3399_CLK_PLL:
240
rk3399_clk_pll_register(sc->clkdom,
241
sc->clks[i].clk.pll);
242
break;
243
case RK_CLK_COMPOSITE:
244
rk_clk_composite_register(sc->clkdom,
245
sc->clks[i].clk.composite);
246
break;
247
case RK_CLK_MUX:
248
rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
249
break;
250
case RK_CLK_ARMCLK:
251
rk_clk_armclk_register(sc->clkdom,
252
sc->clks[i].clk.armclk);
253
break;
254
case RK_CLK_FIXED:
255
clknode_fixed_register(sc->clkdom,
256
sc->clks[i].clk.fixed);
257
break;
258
case RK_CLK_FRACT:
259
rk_clk_fract_register(sc->clkdom,
260
sc->clks[i].clk.fract);
261
break;
262
case RK_CLK_LINK:
263
clknode_link_register(sc->clkdom,
264
sc->clks[i].clk.link);
265
break;
266
default:
267
device_printf(dev, "Unknown clock type\n");
268
return (ENXIO);
269
}
270
}
271
272
if (sc->gates)
273
rk_cru_register_gates(sc);
274
275
if (clkdom_finit(sc->clkdom) != 0)
276
panic("cannot finalize clkdom initialization\n");
277
278
if (bootverbose)
279
clkdom_dump(sc->clkdom);
280
281
clk_set_assigned(dev, node);
282
283
/* register our self as a reset provider */
284
hwreset_register_ofw_provider(dev);
285
286
return (0);
287
}
288
289
static device_method_t rk_cru_methods[] = {
290
/* clkdev interface */
291
DEVMETHOD(clkdev_write_4, rk_cru_write_4),
292
DEVMETHOD(clkdev_read_4, rk_cru_read_4),
293
DEVMETHOD(clkdev_modify_4, rk_cru_modify_4),
294
DEVMETHOD(clkdev_device_lock, rk_cru_device_lock),
295
DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock),
296
297
/* Reset interface */
298
DEVMETHOD(hwreset_assert, rk_cru_reset_assert),
299
DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted),
300
301
DEVMETHOD_END
302
};
303
304
DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
305
sizeof(struct rk_cru_softc));
306
307