177f22241SEmmanuel Vadot /*-
277f22241SEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause
377f22241SEmmanuel Vadot *
477f22241SEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
577f22241SEmmanuel Vadot *
677f22241SEmmanuel Vadot * Redistribution and use in source and binary forms, with or without
777f22241SEmmanuel Vadot * modification, are permitted provided that the following conditions
877f22241SEmmanuel Vadot * are met:
977f22241SEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright
1077f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer.
1177f22241SEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright
1277f22241SEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the
1377f22241SEmmanuel Vadot * documentation and/or other materials provided with the distribution.
1477f22241SEmmanuel Vadot *
1577f22241SEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1677f22241SEmmanuel Vadot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1777f22241SEmmanuel Vadot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1877f22241SEmmanuel Vadot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1977f22241SEmmanuel Vadot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2077f22241SEmmanuel Vadot * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2177f22241SEmmanuel Vadot * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2277f22241SEmmanuel Vadot * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2377f22241SEmmanuel Vadot * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477f22241SEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577f22241SEmmanuel Vadot * SUCH DAMAGE.
2677f22241SEmmanuel Vadot */
2777f22241SEmmanuel Vadot
2877f22241SEmmanuel Vadot /*
2977f22241SEmmanuel Vadot * RockChip Clock and Reset Unit
3077f22241SEmmanuel Vadot */
3177f22241SEmmanuel Vadot
3277f22241SEmmanuel Vadot #include <sys/param.h>
3377f22241SEmmanuel Vadot #include <sys/systm.h>
3477f22241SEmmanuel Vadot #include <sys/bus.h>
3577f22241SEmmanuel Vadot #include <sys/rman.h>
3677f22241SEmmanuel Vadot #include <sys/kernel.h>
3777f22241SEmmanuel Vadot #include <sys/lock.h>
3877f22241SEmmanuel Vadot #include <sys/module.h>
3977f22241SEmmanuel Vadot #include <sys/mutex.h>
4077f22241SEmmanuel Vadot #include <machine/bus.h>
4177f22241SEmmanuel Vadot
4277f22241SEmmanuel Vadot #include <dev/fdt/simplebus.h>
4377f22241SEmmanuel Vadot
4477f22241SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
4577f22241SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
4677f22241SEmmanuel Vadot
47be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
48be82b3a0SEmmanuel Vadot #include <dev/clk/clk_gate.h>
49be82b3a0SEmmanuel Vadot #include <dev/clk/clk_fixed.h>
50be82b3a0SEmmanuel Vadot #include <dev/clk/clk_link.h>
51*1f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
5277f22241SEmmanuel Vadot
5377f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_composite.h>
5477f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_gate.h>
5577f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_mux.h>
5677f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_clk_pll.h>
5777f22241SEmmanuel Vadot #include <dev/clk/rockchip/rk_cru.h>
5877f22241SEmmanuel Vadot
5977f22241SEmmanuel Vadot #include "clkdev_if.h"
6077f22241SEmmanuel Vadot #include "hwreset_if.h"
6177f22241SEmmanuel Vadot
6277f22241SEmmanuel Vadot static struct resource_spec rk_cru_spec[] = {
6377f22241SEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE },
6477f22241SEmmanuel Vadot { -1, 0 }
6577f22241SEmmanuel Vadot };
6677f22241SEmmanuel Vadot
6777f22241SEmmanuel Vadot #define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg))
6877f22241SEmmanuel Vadot #define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
6977f22241SEmmanuel Vadot
7077f22241SEmmanuel Vadot void rk3328_cru_register_clocks(struct rk_cru_softc *sc);
7177f22241SEmmanuel Vadot
7277f22241SEmmanuel Vadot static int
rk_cru_write_4(device_t dev,bus_addr_t addr,uint32_t val)7377f22241SEmmanuel Vadot rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
7477f22241SEmmanuel Vadot {
7577f22241SEmmanuel Vadot struct rk_cru_softc *sc;
7677f22241SEmmanuel Vadot
7777f22241SEmmanuel Vadot sc = device_get_softc(dev);
7877f22241SEmmanuel Vadot CCU_WRITE4(sc, addr, val);
7977f22241SEmmanuel Vadot return (0);
8077f22241SEmmanuel Vadot }
8177f22241SEmmanuel Vadot
8277f22241SEmmanuel Vadot static int
rk_cru_read_4(device_t dev,bus_addr_t addr,uint32_t * val)8377f22241SEmmanuel Vadot rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
8477f22241SEmmanuel Vadot {
8577f22241SEmmanuel Vadot struct rk_cru_softc *sc;
8677f22241SEmmanuel Vadot
8777f22241SEmmanuel Vadot sc = device_get_softc(dev);
8877f22241SEmmanuel Vadot
8977f22241SEmmanuel Vadot *val = CCU_READ4(sc, addr);
9077f22241SEmmanuel Vadot return (0);
9177f22241SEmmanuel Vadot }
9277f22241SEmmanuel Vadot
9377f22241SEmmanuel Vadot static int
rk_cru_modify_4(device_t dev,bus_addr_t addr,uint32_t clr,uint32_t set)9477f22241SEmmanuel Vadot rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
9577f22241SEmmanuel Vadot {
9677f22241SEmmanuel Vadot struct rk_cru_softc *sc;
9777f22241SEmmanuel Vadot uint32_t reg;
9877f22241SEmmanuel Vadot
9977f22241SEmmanuel Vadot sc = device_get_softc(dev);
10077f22241SEmmanuel Vadot
10177f22241SEmmanuel Vadot reg = CCU_READ4(sc, addr);
10277f22241SEmmanuel Vadot reg &= ~clr;
10377f22241SEmmanuel Vadot reg |= set;
10477f22241SEmmanuel Vadot CCU_WRITE4(sc, addr, reg);
10577f22241SEmmanuel Vadot
10677f22241SEmmanuel Vadot return (0);
10777f22241SEmmanuel Vadot }
10877f22241SEmmanuel Vadot
10977f22241SEmmanuel Vadot static int
rk_cru_reset_assert(device_t dev,intptr_t id,bool reset)11077f22241SEmmanuel Vadot rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
11177f22241SEmmanuel Vadot {
11277f22241SEmmanuel Vadot struct rk_cru_softc *sc;
11377f22241SEmmanuel Vadot uint32_t reg;
11477f22241SEmmanuel Vadot int bit;
11577f22241SEmmanuel Vadot uint32_t val;
11677f22241SEmmanuel Vadot
11777f22241SEmmanuel Vadot sc = device_get_softc(dev);
11877f22241SEmmanuel Vadot
11977f22241SEmmanuel Vadot if (id > sc->reset_num)
12077f22241SEmmanuel Vadot return (ENXIO);
12177f22241SEmmanuel Vadot
12277f22241SEmmanuel Vadot reg = sc->reset_offset + id / 16 * 4;
12377f22241SEmmanuel Vadot bit = id % 16;
12477f22241SEmmanuel Vadot
12577f22241SEmmanuel Vadot mtx_lock(&sc->mtx);
12677f22241SEmmanuel Vadot val = 0;
12777f22241SEmmanuel Vadot if (reset)
12877f22241SEmmanuel Vadot val = (1 << bit);
12977f22241SEmmanuel Vadot CCU_WRITE4(sc, reg, val | ((1 << bit) << 16));
13077f22241SEmmanuel Vadot mtx_unlock(&sc->mtx);
13177f22241SEmmanuel Vadot
13277f22241SEmmanuel Vadot return (0);
13377f22241SEmmanuel Vadot }
13477f22241SEmmanuel Vadot
13577f22241SEmmanuel Vadot static int
rk_cru_reset_is_asserted(device_t dev,intptr_t id,bool * reset)13677f22241SEmmanuel Vadot rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
13777f22241SEmmanuel Vadot {
13877f22241SEmmanuel Vadot struct rk_cru_softc *sc;
13977f22241SEmmanuel Vadot uint32_t reg;
14077f22241SEmmanuel Vadot int bit;
14177f22241SEmmanuel Vadot uint32_t val;
14277f22241SEmmanuel Vadot
14377f22241SEmmanuel Vadot sc = device_get_softc(dev);
14477f22241SEmmanuel Vadot
14577f22241SEmmanuel Vadot if (id > sc->reset_num)
14677f22241SEmmanuel Vadot return (ENXIO);
14777f22241SEmmanuel Vadot reg = sc->reset_offset + id / 16 * 4;
14877f22241SEmmanuel Vadot bit = id % 16;
14977f22241SEmmanuel Vadot
15077f22241SEmmanuel Vadot mtx_lock(&sc->mtx);
15177f22241SEmmanuel Vadot val = CCU_READ4(sc, reg);
15277f22241SEmmanuel Vadot mtx_unlock(&sc->mtx);
15377f22241SEmmanuel Vadot
15477f22241SEmmanuel Vadot *reset = false;
15577f22241SEmmanuel Vadot if (val & (1 << bit))
15677f22241SEmmanuel Vadot *reset = true;
15777f22241SEmmanuel Vadot
15877f22241SEmmanuel Vadot return (0);
15977f22241SEmmanuel Vadot }
16077f22241SEmmanuel Vadot
16177f22241SEmmanuel Vadot static void
rk_cru_device_lock(device_t dev)16277f22241SEmmanuel Vadot rk_cru_device_lock(device_t dev)
16377f22241SEmmanuel Vadot {
16477f22241SEmmanuel Vadot struct rk_cru_softc *sc;
16577f22241SEmmanuel Vadot
16677f22241SEmmanuel Vadot sc = device_get_softc(dev);
16777f22241SEmmanuel Vadot mtx_lock(&sc->mtx);
16877f22241SEmmanuel Vadot }
16977f22241SEmmanuel Vadot
17077f22241SEmmanuel Vadot static void
rk_cru_device_unlock(device_t dev)17177f22241SEmmanuel Vadot rk_cru_device_unlock(device_t dev)
17277f22241SEmmanuel Vadot {
17377f22241SEmmanuel Vadot struct rk_cru_softc *sc;
17477f22241SEmmanuel Vadot
17577f22241SEmmanuel Vadot sc = device_get_softc(dev);
17677f22241SEmmanuel Vadot mtx_unlock(&sc->mtx);
17777f22241SEmmanuel Vadot }
17877f22241SEmmanuel Vadot
17977f22241SEmmanuel Vadot static int
rk_cru_register_gates(struct rk_cru_softc * sc)18077f22241SEmmanuel Vadot rk_cru_register_gates(struct rk_cru_softc *sc)
18177f22241SEmmanuel Vadot {
18277f22241SEmmanuel Vadot struct rk_clk_gate_def def;
18377f22241SEmmanuel Vadot int i;
18477f22241SEmmanuel Vadot
18577f22241SEmmanuel Vadot for (i = 0; i < sc->ngates; i++) {
18677f22241SEmmanuel Vadot if (sc->gates[i].name == NULL)
18777f22241SEmmanuel Vadot continue;
18877f22241SEmmanuel Vadot memset(&def, 0, sizeof(def));
18977f22241SEmmanuel Vadot def.clkdef.id = sc->gates[i].id;
19077f22241SEmmanuel Vadot def.clkdef.name = sc->gates[i].name;
19177f22241SEmmanuel Vadot def.clkdef.parent_names = &sc->gates[i].parent_name;
19277f22241SEmmanuel Vadot def.clkdef.parent_cnt = 1;
19377f22241SEmmanuel Vadot def.offset = sc->gates[i].offset;
19477f22241SEmmanuel Vadot def.shift = sc->gates[i].shift;
19577f22241SEmmanuel Vadot def.mask = 1;
19677f22241SEmmanuel Vadot def.on_value = 0;
19777f22241SEmmanuel Vadot def.off_value = 1;
19877f22241SEmmanuel Vadot rk_clk_gate_register(sc->clkdom, &def);
19977f22241SEmmanuel Vadot }
20077f22241SEmmanuel Vadot
20177f22241SEmmanuel Vadot return (0);
20277f22241SEmmanuel Vadot }
20377f22241SEmmanuel Vadot
20477f22241SEmmanuel Vadot int
rk_cru_attach(device_t dev)20577f22241SEmmanuel Vadot rk_cru_attach(device_t dev)
20677f22241SEmmanuel Vadot {
20777f22241SEmmanuel Vadot struct rk_cru_softc *sc;
20877f22241SEmmanuel Vadot phandle_t node;
20977f22241SEmmanuel Vadot int i;
21077f22241SEmmanuel Vadot
21177f22241SEmmanuel Vadot sc = device_get_softc(dev);
21277f22241SEmmanuel Vadot sc->dev = dev;
21377f22241SEmmanuel Vadot
21477f22241SEmmanuel Vadot node = ofw_bus_get_node(dev);
21577f22241SEmmanuel Vadot
21677f22241SEmmanuel Vadot if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
21777f22241SEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n");
21877f22241SEmmanuel Vadot return (ENXIO);
21977f22241SEmmanuel Vadot }
22077f22241SEmmanuel Vadot
22177f22241SEmmanuel Vadot mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
22277f22241SEmmanuel Vadot
22377f22241SEmmanuel Vadot sc->clkdom = clkdom_create(dev);
22477f22241SEmmanuel Vadot if (sc->clkdom == NULL)
22577f22241SEmmanuel Vadot panic("Cannot create clkdom\n");
22677f22241SEmmanuel Vadot
22777f22241SEmmanuel Vadot for (i = 0; i < sc->nclks; i++) {
22877f22241SEmmanuel Vadot switch (sc->clks[i].type) {
22977f22241SEmmanuel Vadot case RK_CLK_UNDEFINED:
23077f22241SEmmanuel Vadot break;
23177f22241SEmmanuel Vadot case RK3066_CLK_PLL:
23277f22241SEmmanuel Vadot rk3066_clk_pll_register(sc->clkdom,
23377f22241SEmmanuel Vadot sc->clks[i].clk.pll);
23477f22241SEmmanuel Vadot break;
23577f22241SEmmanuel Vadot case RK3328_CLK_PLL:
23677f22241SEmmanuel Vadot rk3328_clk_pll_register(sc->clkdom,
23777f22241SEmmanuel Vadot sc->clks[i].clk.pll);
23877f22241SEmmanuel Vadot break;
23977f22241SEmmanuel Vadot case RK3399_CLK_PLL:
24077f22241SEmmanuel Vadot rk3399_clk_pll_register(sc->clkdom,
24177f22241SEmmanuel Vadot sc->clks[i].clk.pll);
24277f22241SEmmanuel Vadot break;
24377f22241SEmmanuel Vadot case RK_CLK_COMPOSITE:
24477f22241SEmmanuel Vadot rk_clk_composite_register(sc->clkdom,
24577f22241SEmmanuel Vadot sc->clks[i].clk.composite);
24677f22241SEmmanuel Vadot break;
24777f22241SEmmanuel Vadot case RK_CLK_MUX:
24877f22241SEmmanuel Vadot rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
24977f22241SEmmanuel Vadot break;
25077f22241SEmmanuel Vadot case RK_CLK_ARMCLK:
25177f22241SEmmanuel Vadot rk_clk_armclk_register(sc->clkdom,
25277f22241SEmmanuel Vadot sc->clks[i].clk.armclk);
25377f22241SEmmanuel Vadot break;
25477f22241SEmmanuel Vadot case RK_CLK_FIXED:
25577f22241SEmmanuel Vadot clknode_fixed_register(sc->clkdom,
25677f22241SEmmanuel Vadot sc->clks[i].clk.fixed);
25777f22241SEmmanuel Vadot break;
25877f22241SEmmanuel Vadot case RK_CLK_FRACT:
25977f22241SEmmanuel Vadot rk_clk_fract_register(sc->clkdom,
26077f22241SEmmanuel Vadot sc->clks[i].clk.fract);
26177f22241SEmmanuel Vadot break;
26277f22241SEmmanuel Vadot case RK_CLK_LINK:
26377f22241SEmmanuel Vadot clknode_link_register(sc->clkdom,
26477f22241SEmmanuel Vadot sc->clks[i].clk.link);
26577f22241SEmmanuel Vadot break;
26677f22241SEmmanuel Vadot default:
26777f22241SEmmanuel Vadot device_printf(dev, "Unknown clock type\n");
26877f22241SEmmanuel Vadot return (ENXIO);
26977f22241SEmmanuel Vadot }
27077f22241SEmmanuel Vadot }
27177f22241SEmmanuel Vadot
27277f22241SEmmanuel Vadot if (sc->gates)
27377f22241SEmmanuel Vadot rk_cru_register_gates(sc);
27477f22241SEmmanuel Vadot
27577f22241SEmmanuel Vadot if (clkdom_finit(sc->clkdom) != 0)
27677f22241SEmmanuel Vadot panic("cannot finalize clkdom initialization\n");
27777f22241SEmmanuel Vadot
27877f22241SEmmanuel Vadot if (bootverbose)
27977f22241SEmmanuel Vadot clkdom_dump(sc->clkdom);
28077f22241SEmmanuel Vadot
28177f22241SEmmanuel Vadot clk_set_assigned(dev, node);
28277f22241SEmmanuel Vadot
28377f22241SEmmanuel Vadot /* register our self as a reset provider */
28477f22241SEmmanuel Vadot hwreset_register_ofw_provider(dev);
28577f22241SEmmanuel Vadot
28677f22241SEmmanuel Vadot return (0);
28777f22241SEmmanuel Vadot }
28877f22241SEmmanuel Vadot
28977f22241SEmmanuel Vadot static device_method_t rk_cru_methods[] = {
29077f22241SEmmanuel Vadot /* clkdev interface */
29177f22241SEmmanuel Vadot DEVMETHOD(clkdev_write_4, rk_cru_write_4),
29277f22241SEmmanuel Vadot DEVMETHOD(clkdev_read_4, rk_cru_read_4),
29377f22241SEmmanuel Vadot DEVMETHOD(clkdev_modify_4, rk_cru_modify_4),
29477f22241SEmmanuel Vadot DEVMETHOD(clkdev_device_lock, rk_cru_device_lock),
29577f22241SEmmanuel Vadot DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock),
29677f22241SEmmanuel Vadot
29777f22241SEmmanuel Vadot /* Reset interface */
29877f22241SEmmanuel Vadot DEVMETHOD(hwreset_assert, rk_cru_reset_assert),
29977f22241SEmmanuel Vadot DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted),
30077f22241SEmmanuel Vadot
30177f22241SEmmanuel Vadot DEVMETHOD_END
30277f22241SEmmanuel Vadot };
30377f22241SEmmanuel Vadot
30477f22241SEmmanuel Vadot DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
30577f22241SEmmanuel Vadot sizeof(struct rk_cru_softc));
306