xref: /freebsd/sys/arm/mv/clk/armada38x_gateclk.c (revision 6f2775548278c76e7c33b15aaaaa759270a8dcd5)
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