xref: /freebsd/sys/arm/mv/clk/armada38x_gateclk.c (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
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 struct armada38x_gateclk_softc
47 {
48 	struct clkdom   *clkdom;
49 	struct mtx  mtx;
50 	const char* parent;
51 };
52 
53 static struct clk_gate_def gateclk_nodes[] =
54 {
55 	{
56 		.clkdef = {
57 			.name = "gateclk-audio",
58 			.id = 0,
59 			.parent_cnt = 1,
60 			.flags = 0,
61 		},
62 		.shift = 0,
63 	},
64 	{
65 		.clkdef = {
66 			.name = "gateclk-eth2",
67 			.id = 2,
68 			.parent_cnt = 1,
69 			.flags = 0,
70 		},
71 		.shift = 2,
72 	},
73 	{
74 		.clkdef = {
75 			.name = "gateclk-eth1",
76 			.id = 3,
77 			.parent_cnt = 1,
78 			.flags = 0,
79 		},
80 		.shift = 3,
81 	},
82 	{
83 		.clkdef = {
84 			.name = "gateclk-eth0",
85 			.id = 4,
86 			.parent_cnt = 1,
87 			.flags = 0,
88 		},
89 		.shift = 4,
90 	},
91 	{
92 		.clkdef = {
93 			.name = "gateclk-mdio",
94 			.id = 4,
95 			.parent_cnt = 1,
96 			.flags = 0,
97 		},
98 		.shift = 4,
99 	},
100 	{
101 		.clkdef = {
102 			.name = "gateclk-usb3h0",
103 			.id = 9,
104 			.parent_cnt = 1,
105 			.flags = 0,
106 		},
107 		.shift = 9,
108 	},
109 	{
110 		.clkdef = {
111 			.name = "gateclk-usb3h1",
112 			.id = 10,
113 			.parent_cnt = 1,
114 			.flags = 0,
115 		},
116 		.shift = 10,
117 	},
118 	{
119 		.clkdef = {
120 			.name = "gateclk-bm",
121 			.id = 13,
122 			.parent_cnt = 1,
123 			.flags = 0,
124 		},
125 		.shift = 13,
126 	},
127 	{
128 		.clkdef = {
129 			.name = "gateclk-crypto0z",
130 			.id = 14,
131 			.parent_cnt = 1,
132 			.flags = 0,
133 		},
134 		.shift = 14,
135 	},
136 	{
137 		.clkdef = {
138 			.name = "gateclk-sata0",
139 			.id = 15,
140 			.parent_cnt = 1,
141 			.flags = 0,
142 		},
143 		.shift = 15,
144 	},
145 	{
146 		.clkdef = {
147 			.name = "gateclk-crypto1z",
148 			.id = 16,
149 			.parent_cnt = 1,
150 			.flags = 0,
151 		},
152 		.shift = 16,
153 	},
154 	{
155 		.clkdef = {
156 			.name = "gateclk-sdio",
157 			.id = 17,
158 			.parent_cnt = 1,
159 			.flags = 0,
160 		},
161 		.shift = 17,
162 	},
163 	{
164 		.clkdef = {
165 			.name = "gateclk-usb2",
166 			.id = 18,
167 			.parent_cnt = 1,
168 			.flags = 0,
169 		},
170 		.shift = 18,
171 	},
172 	{
173 		.clkdef = {
174 			.name = "gateclk-crypto1",
175 			.id = 21,
176 			.parent_cnt = 1,
177 			.flags = 0,
178 		},
179 		.shift = 21,
180 	},
181 	{
182 		.clkdef = {
183 			.name = "gateclk-xor0",
184 			.id = 22,
185 			.parent_cnt = 1,
186 			.flags = 0,
187 		},
188 		.shift = 22,
189 	},
190 	{
191 		.clkdef = {
192 			.name = "gateclk-crypto0",
193 			.id = 23,
194 			.parent_cnt = 1,
195 			.flags = 0,
196 		},
197 		.shift = 23,
198 	},
199 	{
200 		.clkdef = {
201 			.name = "gateclk-xor1",
202 			.id = 28,
203 			.parent_cnt = 1,
204 			.flags = 0,
205 		},
206 		.shift = 28,
207 	},
208 	{
209 		.clkdef = {
210 			.name = "gateclk-sata1",
211 			.id = 30,
212 			.parent_cnt = 1,
213 			.flags = 0,
214 		},
215 		.shift = 30,
216 	}
217 };
218 
219 static int armada38x_gateclk_probe(device_t dev);
220 static int armada38x_gateclk_attach(device_t dev);
221 
222 static device_method_t armada38x_gateclk_methods[] = {
223 	DEVMETHOD(device_probe,		armada38x_gateclk_probe),
224 	DEVMETHOD(device_attach,	armada38x_gateclk_attach),
225 
226 	DEVMETHOD_END
227 };
228 
229 static driver_t armada38x_gateclk_driver = {
230 	"armada38x_gateclk",
231 	armada38x_gateclk_methods,
232 	sizeof(struct armada38x_gateclk_softc),
233 };
234 
235 EARLY_DRIVER_MODULE(armada38x_gateclk, simplebus, armada38x_gateclk_driver, 0, 0,
236 	BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE + 1);
237 
238 static int
239 armada38x_gateclk_probe(device_t dev)
240 {
241 
242 	if (!ofw_bus_status_okay(dev))
243 		return (ENXIO);
244 
245 	if(!ofw_bus_is_compatible(dev, "marvell,armada-380-gating-clock"))
246 		return (ENXIO);
247 
248 	device_set_desc(dev, "ARMADA38X gateclk");
249 
250 	return (BUS_PROBE_DEFAULT);
251 }
252 
253 static int
254 armada38x_gateclk_attach(device_t dev)
255 {
256 	struct armada38x_gateclk_softc *sc;
257 	phandle_t node;
258 	int i, error;
259 	clk_t clock;
260 
261 	sc = device_get_softc(dev);
262 	node = ofw_bus_get_node(dev);
263 
264 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
265 
266 	sc->clkdom = clkdom_create(dev);
267 	if (sc->clkdom == NULL) {
268 		device_printf(dev, "Cannot create clock domain.\n");
269 		return (ENXIO);
270 	}
271 
272 	error = clk_get_by_ofw_index(dev, node, 0, &clock);
273 	if (error > 0)
274 		return (error);
275 
276 	sc->parent = clk_get_name(clock);
277 
278 	for (i = 0; i < nitems(gateclk_nodes); ++i) {
279 		gateclk_nodes[i].clkdef.parent_names = &sc->parent;
280 		error = clknode_gate_register(sc->clkdom, &gateclk_nodes[i]);
281 		if (error != 0) {
282 			device_printf(dev, "Cannot create gate nodes\n");
283 			return (error);
284 		}
285 	}
286 
287 	if (clkdom_finit(sc->clkdom) != 0)
288 		panic("Cannot finalize clock domain initialization.\n");
289 
290 	return (0);
291 }
292