Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/mv/clk/armada38x_gateclk.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2022 Semihalf.
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, BUT
20
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/systm.h>
29
#include <sys/bus.h>
30
#include <sys/rman.h>
31
#include <sys/kernel.h>
32
#include <sys/lock.h>
33
#include <sys/module.h>
34
#include <sys/mutex.h>
35
36
#include <machine/bus.h>
37
38
#include <dev/fdt/simplebus.h>
39
#include <dev/ofw/ofw_bus.h>
40
#include <dev/ofw/ofw_bus_subr.h>
41
#include <dev/clk/clk.h>
42
#include <dev/clk/clk_gate.h>
43
44
#include "clkdev_if.h"
45
46
#define ARMADA38X_GATECLK_MAXREG 0
47
48
static struct resource_spec armada38x_gateclk_specs[] = {
49
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
50
{ -1, 0 }
51
};
52
53
#define RD4(_sc, addr) bus_read_4(_sc->res, addr)
54
#define WR4(_sc, addr, val) bus_write_4(_sc->res, addr, val)
55
56
struct armada38x_gateclk_softc
57
{
58
struct resource *res;
59
struct clkdom *clkdom;
60
struct mtx mtx;
61
const char* parent;
62
};
63
64
static struct clk_gate_def gateclk_nodes[] =
65
{
66
{
67
.clkdef = {
68
.name = "gateclk-audio",
69
.id = 0,
70
.parent_cnt = 1,
71
.flags = 0,
72
},
73
.shift = 0,
74
},
75
{
76
.clkdef = {
77
.name = "gateclk-eth2",
78
.id = 2,
79
.parent_cnt = 1,
80
.flags = 0,
81
},
82
.shift = 2,
83
},
84
{
85
.clkdef = {
86
.name = "gateclk-eth1",
87
.id = 3,
88
.parent_cnt = 1,
89
.flags = 0,
90
},
91
.shift = 3,
92
},
93
{
94
.clkdef = {
95
.name = "gateclk-eth0",
96
.id = 4,
97
.parent_cnt = 1,
98
.flags = 0,
99
},
100
.shift = 4,
101
},
102
{
103
.clkdef = {
104
.name = "gateclk-mdio",
105
.id = 4,
106
.parent_cnt = 1,
107
.flags = 0,
108
},
109
.shift = 4,
110
},
111
{
112
.clkdef = {
113
.name = "gateclk-usb3h0",
114
.id = 9,
115
.parent_cnt = 1,
116
.flags = 0,
117
},
118
.shift = 9,
119
},
120
{
121
.clkdef = {
122
.name = "gateclk-usb3h1",
123
.id = 10,
124
.parent_cnt = 1,
125
.flags = 0,
126
},
127
.shift = 10,
128
},
129
{
130
.clkdef = {
131
.name = "gateclk-bm",
132
.id = 13,
133
.parent_cnt = 1,
134
.flags = 0,
135
},
136
.shift = 13,
137
},
138
{
139
.clkdef = {
140
.name = "gateclk-crypto0z",
141
.id = 14,
142
.parent_cnt = 1,
143
.flags = 0,
144
},
145
.shift = 14,
146
},
147
{
148
.clkdef = {
149
.name = "gateclk-sata0",
150
.id = 15,
151
.parent_cnt = 1,
152
.flags = 0,
153
},
154
.shift = 15,
155
},
156
{
157
.clkdef = {
158
.name = "gateclk-crypto1z",
159
.id = 16,
160
.parent_cnt = 1,
161
.flags = 0,
162
},
163
.shift = 16,
164
},
165
{
166
.clkdef = {
167
.name = "gateclk-sdio",
168
.id = 17,
169
.parent_cnt = 1,
170
.flags = 0,
171
},
172
.shift = 17,
173
},
174
{
175
.clkdef = {
176
.name = "gateclk-usb2",
177
.id = 18,
178
.parent_cnt = 1,
179
.flags = 0,
180
},
181
.shift = 18,
182
},
183
{
184
.clkdef = {
185
.name = "gateclk-crypto1",
186
.id = 21,
187
.parent_cnt = 1,
188
.flags = 0,
189
},
190
.shift = 21,
191
},
192
{
193
.clkdef = {
194
.name = "gateclk-xor0",
195
.id = 22,
196
.parent_cnt = 1,
197
.flags = 0,
198
},
199
.shift = 22,
200
},
201
{
202
.clkdef = {
203
.name = "gateclk-crypto0",
204
.id = 23,
205
.parent_cnt = 1,
206
.flags = 0,
207
},
208
.shift = 23,
209
},
210
{
211
.clkdef = {
212
.name = "gateclk-xor1",
213
.id = 28,
214
.parent_cnt = 1,
215
.flags = 0,
216
},
217
.shift = 28,
218
},
219
{
220
.clkdef = {
221
.name = "gateclk-sata1",
222
.id = 30,
223
.parent_cnt = 1,
224
.flags = 0,
225
},
226
.shift = 30,
227
}
228
};
229
230
static int armada38x_gateclk_probe(device_t dev);
231
static int armada38x_gateclk_attach(device_t dev);
232
233
static int
234
armada38x_gateclk_write_4(device_t dev, bus_addr_t addr, uint32_t val)
235
{
236
struct armada38x_gateclk_softc *sc = device_get_softc(dev);
237
238
if (addr > ARMADA38X_GATECLK_MAXREG)
239
return (EINVAL);
240
241
WR4(sc, addr, val);
242
return (0);
243
}
244
245
static int
246
armada38x_gateclk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
247
{
248
struct armada38x_gateclk_softc *sc = device_get_softc(dev);
249
250
if (addr > ARMADA38X_GATECLK_MAXREG)
251
return (EINVAL);
252
253
*val = RD4(sc, addr);
254
return (0);
255
}
256
257
static int
258
armada38x_gateclk_modify_4(device_t dev, bus_addr_t addr, uint32_t clr,
259
uint32_t set)
260
{
261
struct armada38x_gateclk_softc *sc = device_get_softc(dev);
262
uint32_t reg;
263
264
if (addr > ARMADA38X_GATECLK_MAXREG)
265
return (EINVAL);
266
267
reg = RD4(sc, addr);
268
reg &= ~clr;
269
reg |= set;
270
WR4(sc, addr, reg);
271
272
return (0);
273
}
274
275
static void
276
armada38x_gateclk_device_lock(device_t dev)
277
{
278
struct armada38x_gateclk_softc *sc = device_get_softc(dev);
279
280
mtx_lock(&sc->mtx);
281
}
282
283
static void
284
armada38x_gateclk_device_unlock(device_t dev)
285
{
286
struct armada38x_gateclk_softc *sc = device_get_softc(dev);
287
288
mtx_unlock(&sc->mtx);
289
}
290
291
static device_method_t armada38x_gateclk_methods[] = {
292
DEVMETHOD(device_probe, armada38x_gateclk_probe),
293
DEVMETHOD(device_attach, armada38x_gateclk_attach),
294
295
/* clkdev interface */
296
DEVMETHOD(clkdev_write_4, armada38x_gateclk_write_4),
297
DEVMETHOD(clkdev_read_4, armada38x_gateclk_read_4),
298
DEVMETHOD(clkdev_modify_4, armada38x_gateclk_modify_4),
299
DEVMETHOD(clkdev_device_lock, armada38x_gateclk_device_lock),
300
DEVMETHOD(clkdev_device_unlock, armada38x_gateclk_device_unlock),
301
302
DEVMETHOD_END
303
};
304
305
static driver_t armada38x_gateclk_driver = {
306
"armada38x_gateclk",
307
armada38x_gateclk_methods,
308
sizeof(struct armada38x_gateclk_softc),
309
};
310
311
EARLY_DRIVER_MODULE(armada38x_gateclk, simplebus, armada38x_gateclk_driver, 0, 0,
312
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 1);
313
314
static int
315
armada38x_gateclk_probe(device_t dev)
316
{
317
318
if (!ofw_bus_status_okay(dev))
319
return (ENXIO);
320
321
if(!ofw_bus_is_compatible(dev, "marvell,armada-380-gating-clock"))
322
return (ENXIO);
323
324
device_set_desc(dev, "ARMADA38X gateclk");
325
326
return (BUS_PROBE_DEFAULT);
327
}
328
329
static int
330
armada38x_gateclk_attach(device_t dev)
331
{
332
struct armada38x_gateclk_softc *sc;
333
struct clk_gate_def *defp;
334
phandle_t node;
335
int i, error;
336
clk_t clock;
337
338
sc = device_get_softc(dev);
339
node = ofw_bus_get_node(dev);
340
341
if (bus_alloc_resources(dev, armada38x_gateclk_specs, &sc->res) != 0) {
342
device_printf(dev, "Cannot allocate resources.\n");
343
return (ENXIO);
344
}
345
346
mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
347
348
sc->clkdom = clkdom_create(dev);
349
if (sc->clkdom == NULL) {
350
device_printf(dev, "Cannot create clock domain.\n");
351
return (ENXIO);
352
}
353
354
error = clk_get_by_ofw_index(dev, node, 0, &clock);
355
if (error > 0)
356
return (error);
357
358
sc->parent = clk_get_name(clock);
359
360
for (i = 0; i < nitems(gateclk_nodes); ++i) {
361
/* Fill clk_gate fields. */
362
defp = &gateclk_nodes[i];
363
defp->clkdef.parent_names = &sc->parent;
364
defp->offset = 0;
365
defp->mask = 0x1;
366
defp->on_value = 1;
367
defp->off_value = 0;
368
369
error = clknode_gate_register(sc->clkdom, defp);
370
if (error != 0) {
371
device_printf(dev, "Cannot create gate nodes\n");
372
return (error);
373
}
374
}
375
376
if (clkdom_finit(sc->clkdom) != 0)
377
panic("Cannot finalize clock domain initialization.\n");
378
379
return (0);
380
}
381
382