xref: /freebsd/sys/arm/mv/clk/armada38x_coreclk.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
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/cdefs.h>
28 __FBSDID("$FressBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/mutex.h>
35 #include <sys/rman.h>
36 
37 #include <machine/bus.h>
38 #include <machine/fdt.h>
39 
40 #include <dev/fdt/simplebus.h>
41 #include <dev/ofw/ofw_bus.h>
42 #include <dev/ofw/ofw_bus_subr.h>
43 #include <dev/extres/clk/clk.h>
44 
45 #include <arm/mv/mvwin.h>
46 #include <arm/mv/mvreg.h>
47 #include <arm/mv/mvvar.h>
48 
49 #include <arm/mv/clk/armada38x_gen.h>
50 
51 #include "clkdev_if.h"
52 
53 #define ARMADA38X_CORECLK_MAXREG 0
54 
55 static struct resource_spec armada38x_coreclk_specs[] = {
56 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
57 	{ -1, 0 }
58 };
59 
60 struct armada38x_coreclk_softc {
61 	struct resource	*res;
62 	struct clkdom	*clkdom;
63 	struct mtx	mtx;
64 };
65 
66 static int armada38x_coreclk_attach(device_t dev);
67 static int armada38x_coreclk_probe(device_t dev);
68 
69 static struct armada38x_gen_clknode_def gen_nodes[] =
70 {
71 	{
72 		.def = {
73 			.name = "coreclk_0",
74 			.id = 0,
75 			.parent_cnt = 0,
76 		},
77 	},
78 	{
79 		.def = {
80 			.name = "coreclk_2",
81 			.id = 1,
82 			.parent_cnt = 0,
83 		},
84 	}
85 };
86 
87 static int
88 armada38x_coreclk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
89 {
90 	struct armada38x_coreclk_softc *sc;
91 
92 	sc = device_get_softc(dev);
93 
94 	if (addr > ARMADA38X_CORECLK_MAXREG)
95 		return (EINVAL);
96 
97 	*val = bus_read_4(sc->res, addr);
98 
99 	return (0);
100 }
101 
102 static int
103 armada38x_coreclk_write_4(device_t dev, bus_addr_t addr, uint32_t val)
104 {
105 	struct armada38x_coreclk_softc *sc;
106 
107 	sc = device_get_softc(dev);
108 
109 	if (addr > ARMADA38X_CORECLK_MAXREG)
110 		return (EINVAL);
111 
112 	bus_write_4(sc->res, addr, val);
113 
114 	return (0);
115 }
116 
117 static void
118 armada38x_coreclk_device_lock(device_t dev)
119 {
120 	struct armada38x_coreclk_softc *sc;
121 
122 	sc = device_get_softc(dev);
123 	mtx_lock(&sc->mtx);
124 }
125 
126 static void
127 armada38x_coreclk_device_unlock(device_t dev)
128 {
129 	struct armada38x_coreclk_softc *sc;
130 
131 	sc = device_get_softc(dev);
132 	mtx_unlock(&sc->mtx);
133 }
134 
135 static int
136 armada38x_coreclk_probe(device_t dev)
137 {
138 
139 	if (!ofw_bus_status_okay(dev))
140 		return (ENXIO);
141 
142 	if (!ofw_bus_is_compatible(dev, "marvell,armada-380-core-clock"))
143 		return (ENXIO);
144 
145 	device_set_desc(dev, "ARMADA38X core-clock");
146 
147 	return (BUS_PROBE_DEFAULT);
148 }
149 
150 static int
151 armada38x_coreclk_create_coreclk(device_t dev)
152 {
153 	struct armada38x_coreclk_softc *sc;
154 	int rv, i;
155 
156 	sc = device_get_softc(dev);
157 
158 	for (i = 0; i < nitems(gen_nodes); ++i) {
159 		rv = armada38x_gen_register(sc->clkdom, &gen_nodes[i]);
160 		if (rv)
161 			return (rv);
162 	}
163 
164 	return (rv);
165 }
166 
167 static int
168 armada38x_coreclk_attach(device_t dev)
169 {
170 	struct armada38x_coreclk_softc *sc;
171 	int error;
172 
173 	sc = device_get_softc(dev);
174 
175 	if (bus_alloc_resources(dev, armada38x_coreclk_specs, &sc->res) != 0) {
176 		device_printf(dev, "Cannot allocate resources.\n");
177 		return (ENXIO);
178 	}
179 
180 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
181 
182 	sc->clkdom = clkdom_create(dev);
183 	if (NULL == sc->clkdom) {
184 		device_printf(dev, "Cannot create clkdom\n");
185 		return (ENXIO);
186 	}
187 
188 	error = armada38x_coreclk_create_coreclk(dev);
189 	if (0 != error) {
190 		device_printf(dev, "Cannot create coreclk.\n");
191 		return (error);
192 	}
193 
194 	if (clkdom_finit(sc->clkdom) != 0)
195 		panic("Cannot finalize clock domain initialization.\n");
196 
197 	if (bootverbose)
198 		clkdom_dump(sc->clkdom);
199 
200 	return (0);
201 }
202 
203 static device_method_t amada38x_coreclk_methods[] = {
204 	DEVMETHOD(clkdev_write_4,	armada38x_coreclk_write_4),
205 	DEVMETHOD(clkdev_read_4,	armada38x_coreclk_read_4),
206 	DEVMETHOD(clkdev_device_lock,	armada38x_coreclk_device_lock),
207 	DEVMETHOD(clkdev_device_unlock,	armada38x_coreclk_device_unlock),
208 
209 	DEVMETHOD(device_attach,	armada38x_coreclk_attach),
210 	DEVMETHOD(device_probe,		armada38x_coreclk_probe),
211 
212 	DEVMETHOD_END
213 };
214 
215 static driver_t armada38x_coreclk_driver = {
216 	"armada38x_coreclk",
217 	amada38x_coreclk_methods,
218 	sizeof(struct armada38x_coreclk_softc),
219 };
220 
221 EARLY_DRIVER_MODULE(armada38x_coreclk, simplebus, armada38x_coreclk_driver, 0, 0,
222     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
223