xref: /freebsd/sys/arm/mv/clk/armada38x_coreclk.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
107c5be33SAlbert Jakieła /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
307c5be33SAlbert Jakieła  *
407c5be33SAlbert Jakieła  * Copyright (c) 2022 Semihalf.
507c5be33SAlbert Jakieła  *
607c5be33SAlbert Jakieła  * Redistribution and use in source and binary forms, with or without
707c5be33SAlbert Jakieła  * modification, are permitted provided that the following conditions
807c5be33SAlbert Jakieła  * are met:
907c5be33SAlbert Jakieła  * 1. Redistributions of source code must retain the above copyright
1007c5be33SAlbert Jakieła  *    notice, this list of conditions and the following disclaimer.
1107c5be33SAlbert Jakieła  * 2. Redistributions in binary form must reproduce the above copyright
1207c5be33SAlbert Jakieła  *    notice, this list of conditions and the following disclaimer in the
1307c5be33SAlbert Jakieła  *    documentation and/or other materials provided with the distribution.
1407c5be33SAlbert Jakieła  *
1507c5be33SAlbert Jakieła  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1607c5be33SAlbert Jakieła  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1707c5be33SAlbert Jakieła  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1807c5be33SAlbert Jakieła  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1907c5be33SAlbert Jakieła  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2007c5be33SAlbert Jakieła  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2107c5be33SAlbert Jakieła  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2207c5be33SAlbert Jakieła  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2307c5be33SAlbert Jakieła  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2407c5be33SAlbert Jakieła  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2507c5be33SAlbert Jakieła  */
2607c5be33SAlbert Jakieła 
2707c5be33SAlbert Jakieła #include <sys/param.h>
2807c5be33SAlbert Jakieła #include <sys/bus.h>
2907c5be33SAlbert Jakieła #include <sys/kernel.h>
3007c5be33SAlbert Jakieła #include <sys/module.h>
3107c5be33SAlbert Jakieła #include <sys/mutex.h>
3207c5be33SAlbert Jakieła #include <sys/rman.h>
3307c5be33SAlbert Jakieła 
3407c5be33SAlbert Jakieła #include <machine/bus.h>
3507c5be33SAlbert Jakieła #include <machine/fdt.h>
3607c5be33SAlbert Jakieła 
3707c5be33SAlbert Jakieła #include <dev/fdt/simplebus.h>
3807c5be33SAlbert Jakieła #include <dev/ofw/ofw_bus.h>
3907c5be33SAlbert Jakieła #include <dev/ofw/ofw_bus_subr.h>
40*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
4107c5be33SAlbert Jakieła 
4207c5be33SAlbert Jakieła #include <arm/mv/mvwin.h>
4307c5be33SAlbert Jakieła #include <arm/mv/mvreg.h>
4407c5be33SAlbert Jakieła #include <arm/mv/mvvar.h>
4507c5be33SAlbert Jakieła 
4607c5be33SAlbert Jakieła #include <arm/mv/clk/armada38x_gen.h>
4707c5be33SAlbert Jakieła 
4807c5be33SAlbert Jakieła #include "clkdev_if.h"
4907c5be33SAlbert Jakieła 
5007c5be33SAlbert Jakieła #define ARMADA38X_CORECLK_MAXREG 0
5107c5be33SAlbert Jakieła 
5207c5be33SAlbert Jakieła static struct resource_spec armada38x_coreclk_specs[] = {
5307c5be33SAlbert Jakieła 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
5407c5be33SAlbert Jakieła 	{ -1, 0 }
5507c5be33SAlbert Jakieła };
5607c5be33SAlbert Jakieła 
5707c5be33SAlbert Jakieła struct armada38x_coreclk_softc {
5807c5be33SAlbert Jakieła 	struct resource	*res;
5907c5be33SAlbert Jakieła 	struct clkdom	*clkdom;
6007c5be33SAlbert Jakieła 	struct mtx	mtx;
6107c5be33SAlbert Jakieła };
6207c5be33SAlbert Jakieła 
6307c5be33SAlbert Jakieła static int armada38x_coreclk_attach(device_t dev);
6407c5be33SAlbert Jakieła static int armada38x_coreclk_probe(device_t dev);
6507c5be33SAlbert Jakieła 
6607c5be33SAlbert Jakieła static struct armada38x_gen_clknode_def gen_nodes[] =
6707c5be33SAlbert Jakieła {
6807c5be33SAlbert Jakieła 	{
6907c5be33SAlbert Jakieła 		.def = {
7007c5be33SAlbert Jakieła 			.name = "coreclk_0",
7107c5be33SAlbert Jakieła 			.id = 0,
7207c5be33SAlbert Jakieła 			.parent_cnt = 0,
7307c5be33SAlbert Jakieła 		},
7407c5be33SAlbert Jakieła 	},
7507c5be33SAlbert Jakieła 	{
7607c5be33SAlbert Jakieła 		.def = {
7707c5be33SAlbert Jakieła 			.name = "coreclk_2",
7807c5be33SAlbert Jakieła 			.id = 1,
7907c5be33SAlbert Jakieła 			.parent_cnt = 0,
8007c5be33SAlbert Jakieła 		},
8107c5be33SAlbert Jakieła 	}
8207c5be33SAlbert Jakieła };
8307c5be33SAlbert Jakieła 
8407c5be33SAlbert Jakieła static int
armada38x_coreclk_read_4(device_t dev,bus_addr_t addr,uint32_t * val)8507c5be33SAlbert Jakieła armada38x_coreclk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
8607c5be33SAlbert Jakieła {
8707c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
8807c5be33SAlbert Jakieła 
8907c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
9007c5be33SAlbert Jakieła 
9107c5be33SAlbert Jakieła 	if (addr > ARMADA38X_CORECLK_MAXREG)
9207c5be33SAlbert Jakieła 		return (EINVAL);
9307c5be33SAlbert Jakieła 
9407c5be33SAlbert Jakieła 	*val = bus_read_4(sc->res, addr);
9507c5be33SAlbert Jakieła 
9607c5be33SAlbert Jakieła 	return (0);
9707c5be33SAlbert Jakieła }
9807c5be33SAlbert Jakieła 
9907c5be33SAlbert Jakieła static int
armada38x_coreclk_write_4(device_t dev,bus_addr_t addr,uint32_t val)10007c5be33SAlbert Jakieła armada38x_coreclk_write_4(device_t dev, bus_addr_t addr, uint32_t val)
10107c5be33SAlbert Jakieła {
10207c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
10307c5be33SAlbert Jakieła 
10407c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
10507c5be33SAlbert Jakieła 
10607c5be33SAlbert Jakieła 	if (addr > ARMADA38X_CORECLK_MAXREG)
10707c5be33SAlbert Jakieła 		return (EINVAL);
10807c5be33SAlbert Jakieła 
10907c5be33SAlbert Jakieła 	bus_write_4(sc->res, addr, val);
11007c5be33SAlbert Jakieła 
11107c5be33SAlbert Jakieła 	return (0);
11207c5be33SAlbert Jakieła }
11307c5be33SAlbert Jakieła 
11407c5be33SAlbert Jakieła static void
armada38x_coreclk_device_lock(device_t dev)11507c5be33SAlbert Jakieła armada38x_coreclk_device_lock(device_t dev)
11607c5be33SAlbert Jakieła {
11707c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
11807c5be33SAlbert Jakieła 
11907c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
12007c5be33SAlbert Jakieła 	mtx_lock(&sc->mtx);
12107c5be33SAlbert Jakieła }
12207c5be33SAlbert Jakieła 
12307c5be33SAlbert Jakieła static void
armada38x_coreclk_device_unlock(device_t dev)12407c5be33SAlbert Jakieła armada38x_coreclk_device_unlock(device_t dev)
12507c5be33SAlbert Jakieła {
12607c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
12707c5be33SAlbert Jakieła 
12807c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
12907c5be33SAlbert Jakieła 	mtx_unlock(&sc->mtx);
13007c5be33SAlbert Jakieła }
13107c5be33SAlbert Jakieła 
13207c5be33SAlbert Jakieła static int
armada38x_coreclk_probe(device_t dev)13307c5be33SAlbert Jakieła armada38x_coreclk_probe(device_t dev)
13407c5be33SAlbert Jakieła {
13507c5be33SAlbert Jakieła 
13607c5be33SAlbert Jakieła 	if (!ofw_bus_status_okay(dev))
13707c5be33SAlbert Jakieła 		return (ENXIO);
13807c5be33SAlbert Jakieła 
13907c5be33SAlbert Jakieła 	if (!ofw_bus_is_compatible(dev, "marvell,armada-380-core-clock"))
14007c5be33SAlbert Jakieła 		return (ENXIO);
14107c5be33SAlbert Jakieła 
14207c5be33SAlbert Jakieła 	device_set_desc(dev, "ARMADA38X core-clock");
14307c5be33SAlbert Jakieła 
14407c5be33SAlbert Jakieła 	return (BUS_PROBE_DEFAULT);
14507c5be33SAlbert Jakieła }
14607c5be33SAlbert Jakieła 
14707c5be33SAlbert Jakieła static int
armada38x_coreclk_create_coreclk(device_t dev)14807c5be33SAlbert Jakieła armada38x_coreclk_create_coreclk(device_t dev)
14907c5be33SAlbert Jakieła {
15007c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
15107c5be33SAlbert Jakieła 	int rv, i;
15207c5be33SAlbert Jakieła 
15307c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
15407c5be33SAlbert Jakieła 
15507c5be33SAlbert Jakieła 	for (i = 0; i < nitems(gen_nodes); ++i) {
15607c5be33SAlbert Jakieła 		rv = armada38x_gen_register(sc->clkdom, &gen_nodes[i]);
15707c5be33SAlbert Jakieła 		if (rv)
15807c5be33SAlbert Jakieła 			return (rv);
15907c5be33SAlbert Jakieła 	}
16007c5be33SAlbert Jakieła 
16107c5be33SAlbert Jakieła 	return (rv);
16207c5be33SAlbert Jakieła }
16307c5be33SAlbert Jakieła 
16407c5be33SAlbert Jakieła static int
armada38x_coreclk_attach(device_t dev)16507c5be33SAlbert Jakieła armada38x_coreclk_attach(device_t dev)
16607c5be33SAlbert Jakieła {
16707c5be33SAlbert Jakieła 	struct armada38x_coreclk_softc *sc;
16807c5be33SAlbert Jakieła 	int error;
16907c5be33SAlbert Jakieła 
17007c5be33SAlbert Jakieła 	sc = device_get_softc(dev);
17107c5be33SAlbert Jakieła 
17207c5be33SAlbert Jakieła 	if (bus_alloc_resources(dev, armada38x_coreclk_specs, &sc->res) != 0) {
17307c5be33SAlbert Jakieła 		device_printf(dev, "Cannot allocate resources.\n");
17407c5be33SAlbert Jakieła 		return (ENXIO);
17507c5be33SAlbert Jakieła 	}
17607c5be33SAlbert Jakieła 
17707c5be33SAlbert Jakieła 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
17807c5be33SAlbert Jakieła 
17907c5be33SAlbert Jakieła 	sc->clkdom = clkdom_create(dev);
18007c5be33SAlbert Jakieła 	if (NULL == sc->clkdom) {
18107c5be33SAlbert Jakieła 		device_printf(dev, "Cannot create clkdom\n");
18207c5be33SAlbert Jakieła 		return (ENXIO);
18307c5be33SAlbert Jakieła 	}
18407c5be33SAlbert Jakieła 
18507c5be33SAlbert Jakieła 	error = armada38x_coreclk_create_coreclk(dev);
18607c5be33SAlbert Jakieła 	if (0 != error) {
18707c5be33SAlbert Jakieła 		device_printf(dev, "Cannot create coreclk.\n");
18807c5be33SAlbert Jakieła 		return (error);
18907c5be33SAlbert Jakieła 	}
19007c5be33SAlbert Jakieła 
19107c5be33SAlbert Jakieła 	if (clkdom_finit(sc->clkdom) != 0)
19207c5be33SAlbert Jakieła 		panic("Cannot finalize clock domain initialization.\n");
19307c5be33SAlbert Jakieła 
19407c5be33SAlbert Jakieła 	if (bootverbose)
19507c5be33SAlbert Jakieła 		clkdom_dump(sc->clkdom);
19607c5be33SAlbert Jakieła 
19707c5be33SAlbert Jakieła 	return (0);
19807c5be33SAlbert Jakieła }
19907c5be33SAlbert Jakieła 
20007c5be33SAlbert Jakieła static device_method_t amada38x_coreclk_methods[] = {
20107c5be33SAlbert Jakieła 	DEVMETHOD(clkdev_write_4,	armada38x_coreclk_write_4),
20207c5be33SAlbert Jakieła 	DEVMETHOD(clkdev_read_4,	armada38x_coreclk_read_4),
20307c5be33SAlbert Jakieła 	DEVMETHOD(clkdev_device_lock,	armada38x_coreclk_device_lock),
20407c5be33SAlbert Jakieła 	DEVMETHOD(clkdev_device_unlock,	armada38x_coreclk_device_unlock),
20507c5be33SAlbert Jakieła 
20607c5be33SAlbert Jakieła 	DEVMETHOD(device_attach,	armada38x_coreclk_attach),
20707c5be33SAlbert Jakieła 	DEVMETHOD(device_probe,		armada38x_coreclk_probe),
20807c5be33SAlbert Jakieła 
20907c5be33SAlbert Jakieła 	DEVMETHOD_END
21007c5be33SAlbert Jakieła };
21107c5be33SAlbert Jakieła 
21207c5be33SAlbert Jakieła static driver_t armada38x_coreclk_driver = {
21307c5be33SAlbert Jakieła 	"armada38x_coreclk",
21407c5be33SAlbert Jakieła 	amada38x_coreclk_methods,
21507c5be33SAlbert Jakieła 	sizeof(struct armada38x_coreclk_softc),
21607c5be33SAlbert Jakieła };
21707c5be33SAlbert Jakieła 
21807c5be33SAlbert Jakieła EARLY_DRIVER_MODULE(armada38x_coreclk, simplebus, armada38x_coreclk_driver, 0, 0,
21907c5be33SAlbert Jakieła     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
220