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
52static struct resource_spec armada38x_coreclk_specs[] = {
53	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
54	{ -1, 0 }
55};
56
57struct armada38x_coreclk_softc {
58	struct resource	*res;
59	struct clkdom	*clkdom;
60	struct mtx	mtx;
61};
62
63static int armada38x_coreclk_attach(device_t dev);
64static int armada38x_coreclk_probe(device_t dev);
65
66static 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
84static int
85armada38x_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
99static int
100armada38x_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
114static void
115armada38x_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
123static void
124armada38x_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
132static int
133armada38x_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
147static int
148armada38x_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
164static int
165armada38x_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
200static 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
212static driver_t armada38x_coreclk_driver = {
213	"armada38x_coreclk",
214	amada38x_coreclk_methods,
215	sizeof(struct armada38x_coreclk_softc),
216};
217
218EARLY_DRIVER_MODULE(armada38x_coreclk, simplebus, armada38x_coreclk_driver, 0, 0,
219    BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
220