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