xref: /f-stack/freebsd/arm64/rockchip/clk/rk_cru.c (revision 22ce4aff)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <[email protected]>
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,
20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 /*
31  * RockChip Clock and Reset Unit
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/bus.h>
40 #include <sys/rman.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/module.h>
44 #include <sys/mutex.h>
45 #include <machine/bus.h>
46 
47 #include <dev/fdt/simplebus.h>
48 
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51 
52 #include <dev/extres/clk/clk.h>
53 #include <dev/extres/clk/clk_gate.h>
54 #include <dev/extres/clk/clk_fixed.h>
55 #include <dev/extres/clk/clk_link.h>
56 #include <dev/extres/hwreset/hwreset.h>
57 
58 #include <arm64/rockchip/clk/rk_clk_composite.h>
59 #include <arm64/rockchip/clk/rk_clk_gate.h>
60 #include <arm64/rockchip/clk/rk_clk_mux.h>
61 #include <arm64/rockchip/clk/rk_clk_pll.h>
62 #include <arm64/rockchip/clk/rk_cru.h>
63 
64 #include "clkdev_if.h"
65 #include "hwreset_if.h"
66 
67 static struct resource_spec rk_cru_spec[] = {
68 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
69 	{ -1, 0 }
70 };
71 
72 #define	CCU_READ4(sc, reg)		bus_read_4((sc)->res, (reg))
73 #define	CCU_WRITE4(sc, reg, val)	bus_write_4((sc)->res, (reg), (val))
74 
75 void	rk3328_cru_register_clocks(struct rk_cru_softc *sc);
76 
77 static int
rk_cru_write_4(device_t dev,bus_addr_t addr,uint32_t val)78 rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
79 {
80 	struct rk_cru_softc *sc;
81 
82 	sc = device_get_softc(dev);
83 	CCU_WRITE4(sc, addr, val);
84 	return (0);
85 }
86 
87 static int
rk_cru_read_4(device_t dev,bus_addr_t addr,uint32_t * val)88 rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
89 {
90 	struct rk_cru_softc *sc;
91 
92 	sc = device_get_softc(dev);
93 
94 	*val = CCU_READ4(sc, addr);
95 	return (0);
96 }
97 
98 static int
rk_cru_modify_4(device_t dev,bus_addr_t addr,uint32_t clr,uint32_t set)99 rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
100 {
101 	struct rk_cru_softc *sc;
102 	uint32_t reg;
103 
104 	sc = device_get_softc(dev);
105 
106 	reg = CCU_READ4(sc, addr);
107 	reg &= ~clr;
108 	reg |= set;
109 	CCU_WRITE4(sc, addr, reg);
110 
111 	return (0);
112 }
113 
114 static int
rk_cru_reset_assert(device_t dev,intptr_t id,bool reset)115 rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
116 {
117 	struct rk_cru_softc *sc;
118 	uint32_t reg;
119 	int bit;
120 	uint32_t val;
121 
122 	sc = device_get_softc(dev);
123 
124 	if (id > sc->reset_num)
125 		return (ENXIO);
126 
127 	reg = sc->reset_offset + id / 16 * 4;
128 	bit = id % 16;
129 
130 	mtx_lock(&sc->mtx);
131 	val = 0;
132 	if (reset)
133 		val = (1 << bit);
134 	CCU_WRITE4(sc, reg, val | ((1 << bit) << 16));
135 	mtx_unlock(&sc->mtx);
136 
137 	return (0);
138 }
139 
140 static int
rk_cru_reset_is_asserted(device_t dev,intptr_t id,bool * reset)141 rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
142 {
143 	struct rk_cru_softc *sc;
144 	uint32_t reg;
145 	int bit;
146 	uint32_t val;
147 
148 	sc = device_get_softc(dev);
149 
150 	if (id > sc->reset_num)
151 		return (ENXIO);
152 	reg = sc->reset_offset + id / 16 * 4;
153 	bit = id % 16;
154 
155 	mtx_lock(&sc->mtx);
156 	val = CCU_READ4(sc, reg);
157 	mtx_unlock(&sc->mtx);
158 
159 	*reset = false;
160 	if (val & (1 << bit))
161 		*reset = true;
162 
163 	return (0);
164 }
165 
166 static void
rk_cru_device_lock(device_t dev)167 rk_cru_device_lock(device_t dev)
168 {
169 	struct rk_cru_softc *sc;
170 
171 	sc = device_get_softc(dev);
172 	mtx_lock(&sc->mtx);
173 }
174 
175 static void
rk_cru_device_unlock(device_t dev)176 rk_cru_device_unlock(device_t dev)
177 {
178 	struct rk_cru_softc *sc;
179 
180 	sc = device_get_softc(dev);
181 	mtx_unlock(&sc->mtx);
182 }
183 
184 static int
rk_cru_register_gates(struct rk_cru_softc * sc)185 rk_cru_register_gates(struct rk_cru_softc *sc)
186 {
187 	struct rk_clk_gate_def def;
188 	int i;
189 
190 	for (i = 0; i < sc->ngates; i++) {
191 		if (sc->gates[i].name == NULL)
192 			continue;
193 		memset(&def, 0, sizeof(def));
194 		def.clkdef.id = sc->gates[i].id;
195 		def.clkdef.name = sc->gates[i].name;
196 		def.clkdef.parent_names = &sc->gates[i].parent_name;
197 		def.clkdef.parent_cnt = 1;
198 		def.offset = sc->gates[i].offset;
199 		def.shift = sc->gates[i].shift;
200 		def.mask = 1;
201 		def.on_value = 0;
202 		def.off_value = 1;
203 		rk_clk_gate_register(sc->clkdom, &def);
204 	}
205 
206 	return (0);
207 }
208 
209 int
rk_cru_attach(device_t dev)210 rk_cru_attach(device_t dev)
211 {
212 	struct rk_cru_softc *sc;
213 	phandle_t node;
214 	int	i;
215 
216 	sc = device_get_softc(dev);
217 	sc->dev = dev;
218 
219 	node = ofw_bus_get_node(dev);
220 
221 	if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
222 		device_printf(dev, "cannot allocate resources for device\n");
223 		return (ENXIO);
224 	}
225 
226 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
227 
228 	sc->clkdom = clkdom_create(dev);
229 	if (sc->clkdom == NULL)
230 		panic("Cannot create clkdom\n");
231 
232 	for (i = 0; i < sc->nclks; i++) {
233 		switch (sc->clks[i].type) {
234 		case RK_CLK_UNDEFINED:
235 			break;
236 		case RK3066_CLK_PLL:
237 			rk3066_clk_pll_register(sc->clkdom,
238 			    sc->clks[i].clk.pll);
239 			break;
240 		case RK3328_CLK_PLL:
241 			rk3328_clk_pll_register(sc->clkdom,
242 			    sc->clks[i].clk.pll);
243 			break;
244 		case RK3399_CLK_PLL:
245 			rk3399_clk_pll_register(sc->clkdom,
246 			    sc->clks[i].clk.pll);
247 			break;
248 		case RK_CLK_COMPOSITE:
249 			rk_clk_composite_register(sc->clkdom,
250 			    sc->clks[i].clk.composite);
251 			break;
252 		case RK_CLK_MUX:
253 			rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
254 			break;
255 		case RK_CLK_ARMCLK:
256 			rk_clk_armclk_register(sc->clkdom,
257 			    sc->clks[i].clk.armclk);
258 			break;
259 		case RK_CLK_FIXED:
260 			clknode_fixed_register(sc->clkdom,
261 			    sc->clks[i].clk.fixed);
262 			break;
263 		case RK_CLK_FRACT:
264 			rk_clk_fract_register(sc->clkdom,
265 			    sc->clks[i].clk.fract);
266 			break;
267 		case RK_CLK_LINK:
268 			clknode_link_register(sc->clkdom,
269 			    sc->clks[i].clk.link);
270 			break;
271 		default:
272 			device_printf(dev, "Unknown clock type\n");
273 			return (ENXIO);
274 		}
275 	}
276 
277 	if (sc->gates)
278 		rk_cru_register_gates(sc);
279 
280 	if (clkdom_finit(sc->clkdom) != 0)
281 		panic("cannot finalize clkdom initialization\n");
282 
283 	if (bootverbose)
284 		clkdom_dump(sc->clkdom);
285 
286 	clk_set_assigned(dev, node);
287 
288 	/* register our self as a reset provider */
289 	hwreset_register_ofw_provider(dev);
290 
291 	return (0);
292 }
293 
294 static device_method_t rk_cru_methods[] = {
295 	/* clkdev interface */
296 	DEVMETHOD(clkdev_write_4,	rk_cru_write_4),
297 	DEVMETHOD(clkdev_read_4,	rk_cru_read_4),
298 	DEVMETHOD(clkdev_modify_4,	rk_cru_modify_4),
299 	DEVMETHOD(clkdev_device_lock,	rk_cru_device_lock),
300 	DEVMETHOD(clkdev_device_unlock,	rk_cru_device_unlock),
301 
302 	/* Reset interface */
303 	DEVMETHOD(hwreset_assert,	rk_cru_reset_assert),
304 	DEVMETHOD(hwreset_is_asserted,	rk_cru_reset_is_asserted),
305 
306 	DEVMETHOD_END
307 };
308 
309 DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
310     sizeof(struct rk_cru_softc));
311