]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/rockchip/clk/rk_cru.c
Update to Zstandard 1.3.8
[FreeBSD/FreeBSD.git] / sys / arm64 / rockchip / clk / rk_cru.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 /*
32  * RockChip Clock and Reset Unit
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/rman.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <machine/bus.h>
45
46 #include <dev/fdt/simplebus.h>
47
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <dev/extres/clk/clk.h>
52 #include <dev/extres/clk/clk_gate.h>
53 #include <dev/extres/hwreset/hwreset.h>
54
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>
60
61 #include "clkdev_if.h"
62 #include "hwreset_if.h"
63
64 static struct resource_spec rk_cru_spec[] = {
65         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
66         { -1, 0 }
67 };
68
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))
71
72 void    rk3328_cru_register_clocks(struct rk_cru_softc *sc);
73
74 static int
75 rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val)
76 {
77         struct rk_cru_softc *sc;
78
79         sc = device_get_softc(dev);
80         CCU_WRITE4(sc, addr, val);
81         return (0);
82 }
83
84 static int
85 rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
86 {
87         struct rk_cru_softc *sc;
88
89         sc = device_get_softc(dev);
90
91         *val = CCU_READ4(sc, addr);
92         return (0);
93 }
94
95 static int
96 rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
97 {
98         struct rk_cru_softc *sc;
99         uint32_t reg;
100
101         sc = device_get_softc(dev);
102
103         reg = CCU_READ4(sc, addr);
104         reg &= ~clr;
105         reg |= set;
106         CCU_WRITE4(sc, addr, reg);
107
108         return (0);
109 }
110
111 static int
112 rk_cru_reset_assert(device_t dev, intptr_t id, bool reset)
113 {
114         struct rk_cru_softc *sc;
115         uint32_t val;
116
117         sc = device_get_softc(dev);
118
119         if (id >= sc->nresets || sc->resets[id].offset == 0)
120                 return (0);
121
122         mtx_lock(&sc->mtx);
123         val = CCU_READ4(sc, sc->resets[id].offset);
124         if (reset)
125                 val &= ~(1 << sc->resets[id].shift);
126         else
127                 val |= 1 << sc->resets[id].shift;
128         CCU_WRITE4(sc, sc->resets[id].offset, val);
129         mtx_unlock(&sc->mtx);
130
131         return (0);
132 }
133
134 static int
135 rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
136 {
137         struct rk_cru_softc *sc;
138         uint32_t val;
139
140         sc = device_get_softc(dev);
141
142         if (id >= sc->nresets || sc->resets[id].offset == 0)
143                 return (0);
144
145         mtx_lock(&sc->mtx);
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);
149
150         return (0);
151 }
152
153 static void
154 rk_cru_device_lock(device_t dev)
155 {
156         struct rk_cru_softc *sc;
157
158         sc = device_get_softc(dev);
159         mtx_lock(&sc->mtx);
160 }
161
162 static void
163 rk_cru_device_unlock(device_t dev)
164 {
165         struct rk_cru_softc *sc;
166
167         sc = device_get_softc(dev);
168         mtx_unlock(&sc->mtx);
169 }
170
171 static int
172 rk_cru_register_gates(struct rk_cru_softc *sc)
173 {
174         struct rk_clk_gate_def def;
175         int i;
176
177         for (i = 0; i < sc->ngates; i++) {
178                 if (sc->gates[i].name == NULL)
179                         continue;
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;
187                 def.mask = 1;
188                 def.on_value = 0;
189                 def.off_value = 1;
190                 rk_clk_gate_register(sc->clkdom, &def);
191         }
192
193         return (0);
194 }
195
196 int
197 rk_cru_attach(device_t dev)
198 {
199         struct rk_cru_softc *sc;
200         phandle_t node;
201         int     i;
202
203         sc = device_get_softc(dev);
204         sc->dev = dev;
205
206         node = ofw_bus_get_node(dev);
207
208         if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) {
209                 device_printf(dev, "cannot allocate resources for device\n");
210                 return (ENXIO);
211         }
212
213         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
214
215         sc->clkdom = clkdom_create(dev);
216         if (sc->clkdom == NULL)
217                 panic("Cannot create clkdom\n");
218
219         for (i = 0; i < sc->nclks; i++) {
220                 switch (sc->clks[i].type) {
221                 case RK_CLK_UNDEFINED:
222                         break;
223                 case RK3328_CLK_PLL:
224                         rk3328_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
225                         break;
226                 case RK3399_CLK_PLL:
227                         rk3399_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll);
228                         break;
229                 case RK_CLK_COMPOSITE:
230                         rk_clk_composite_register(sc->clkdom,
231                             sc->clks[i].clk.composite);
232                         break;
233                 case RK_CLK_MUX:
234                         rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
235                         break;
236                 case RK_CLK_ARMCLK:
237                         rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk);
238                         break;
239                 default:
240                         device_printf(dev, "Unknown clock type\n");
241                         return (ENXIO);
242                         break;
243                 }
244         }
245         if (sc->gates)
246                 rk_cru_register_gates(sc);
247
248         if (clkdom_finit(sc->clkdom) != 0)
249                 panic("cannot finalize clkdom initialization\n");
250
251         if (bootverbose)
252                 clkdom_dump(sc->clkdom);
253
254         clk_set_assigned(dev, node);
255
256         /* If we have resets, register our self as a reset provider */
257         if (sc->resets)
258                 hwreset_register_ofw_provider(dev);
259
260         return (0);
261 }
262
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),
270
271         /* Reset interface */
272         DEVMETHOD(hwreset_assert,       rk_cru_reset_assert),
273         DEVMETHOD(hwreset_is_asserted,  rk_cru_reset_is_asserted),
274
275         DEVMETHOD_END
276 };
277
278 DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods,
279     sizeof(struct rk_cru_softc));