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