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