2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * RockChip Clock and Reset Unit
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <machine/bus.h>
46 #include <dev/fdt/simplebus.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
51 #include <dev/extres/clk/clk.h>
52 #include <dev/extres/clk/clk_gate.h>
53 #include <dev/extres/hwreset/hwreset.h>
55 #include <arm64/rockchip/clk/rk_clk_composite.h>
56 #include <arm64/rockchip/clk/rk_clk_gate.h>
57 #include <arm64/rockchip/clk/rk_clk_mux.h>
58 #include <arm64/rockchip/clk/rk_clk_pll.h>
59 #include <arm64/rockchip/clk/rk_cru.h>
61 #include "clkdev_if.h"
62 #include "hwreset_if.h"
64 static struct resource_spec rk_cru_spec[] = {
65 { SYS_RES_MEMORY, 0, RF_ACTIVE },
69 #define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg))
70 #define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
72 void rk3328_cru_register_clocks(struct rk_cru_softc *sc);
75 rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
77 struct rk_cru_softc *sc;
79 sc = device_get_softc(dev);
80 CCU_WRITE4(sc, addr, val);
85 rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
87 struct rk_cru_softc *sc;
89 sc = device_get_softc(dev);
91 *val = CCU_READ4(sc, addr);
96 rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
98 struct rk_cru_softc *sc;
101 sc = device_get_softc(dev);
103 reg = CCU_READ4(sc, addr);
106 CCU_WRITE4(sc, addr, reg);
112 rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
114 struct rk_cru_softc *sc;
117 sc = device_get_softc(dev);
119 if (id >= sc->nresets || sc->resets[id].offset == 0)
123 val = CCU_READ4(sc, sc->resets[id].offset);
125 val &= ~(1 << sc->resets[id].shift);
127 val |= 1 << sc->resets[id].shift;
128 CCU_WRITE4(sc, sc->resets[id].offset, val);
129 mtx_unlock(&sc->mtx);
135 rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
137 struct rk_cru_softc *sc;
140 sc = device_get_softc(dev);
142 if (id >= sc->nresets || sc->resets[id].offset == 0)
146 val = CCU_READ4(sc, sc->resets[id].offset);
147 *reset = (val & (1 << sc->resets[id].shift)) != 0 ? false : true;
148 mtx_unlock(&sc->mtx);
154 rk_cru_device_lock(device_t dev)
156 struct rk_cru_softc *sc;
158 sc = device_get_softc(dev);
163 rk_cru_device_unlock(device_t dev)
165 struct rk_cru_softc *sc;
167 sc = device_get_softc(dev);
168 mtx_unlock(&sc->mtx);
172 rk_cru_register_gates(struct rk_cru_softc *sc)
174 struct rk_clk_gate_def def;
177 for (i = 0; i < sc->ngates; i++) {
178 if (sc->gates[i].name == NULL)
180 memset(&def, 0, sizeof(def));
181 def.clkdef.id = sc->gates[i].id;
182 def.clkdef.name = sc->gates[i].name;
183 def.clkdef.parent_names = &sc->gates[i].parent_name;
184 def.clkdef.parent_cnt = 1;
185 def.offset = sc->gates[i].offset;
186 def.shift = sc->gates[i].shift;
190 rk_clk_gate_register(sc->clkdom, &def);
197 rk_cru_attach(device_t dev)
199 struct rk_cru_softc *sc;
203 sc = device_get_softc(dev);
206 node = ofw_bus_get_node(dev);
208 if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
209 device_printf(dev, "cannot allocate resources for device\n");
213 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
215 sc->clkdom = clkdom_create(dev);
216 if (sc->clkdom == NULL)
217 panic("Cannot create clkdom\n");
219 for (i = 0; i < sc->nclks; i++) {
220 switch (sc->clks[i].type) {
221 case RK_CLK_UNDEFINED:
224 rk3328_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
227 rk3399_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
229 case RK_CLK_COMPOSITE:
230 rk_clk_composite_register(sc->clkdom,
231 sc->clks[i].clk.composite);
234 rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
237 rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk);
240 device_printf(dev, "Unknown clock type\n");
246 rk_cru_register_gates(sc);
248 if (clkdom_finit(sc->clkdom) != 0)
249 panic("cannot finalize clkdom initialization\n");
252 clkdom_dump(sc->clkdom);
254 clk_set_assigned(dev, node);
256 /* If we have resets, register our self as a reset provider */
258 hwreset_register_ofw_provider(dev);
263 static device_method_t rk_cru_methods[] = {
264 /* clkdev interface */
265 DEVMETHOD(clkdev_write_4, rk_cru_write_4),
266 DEVMETHOD(clkdev_read_4, rk_cru_read_4),
267 DEVMETHOD(clkdev_modify_4, rk_cru_modify_4),
268 DEVMETHOD(clkdev_device_lock, rk_cru_device_lock),
269 DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock),
271 /* Reset interface */
272 DEVMETHOD(hwreset_assert, rk_cru_reset_assert),
273 DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted),
278 DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
279 sizeof(struct rk_cru_softc));