1*be9fefafSTom Jones /*-
2*be9fefafSTom Jones * SPDX-License-Identifier: BSD-2-Clause
3*be9fefafSTom Jones *
4*be9fefafSTom Jones * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
5*be9fefafSTom Jones * Copyright (c) 2024 The FreeBSD Foundation
6*be9fefafSTom Jones *
7*be9fefafSTom Jones * Portions of this software were developed by Tom Jones <thj@freebsd.org>
8*be9fefafSTom Jones * under sponsorship from the FreeBSD Foundation.
9*be9fefafSTom Jones *
10*be9fefafSTom Jones * Redistribution and use in source and binary forms, with or without
11*be9fefafSTom Jones * modification, are permitted provided that the following conditions
12*be9fefafSTom Jones * are met:
13*be9fefafSTom Jones * 1. Redistributions of source code must retain the above copyright
14*be9fefafSTom Jones * notice, this list of conditions and the following disclaimer.
15*be9fefafSTom Jones * 2. Redistributions in binary form must reproduce the above copyright
16*be9fefafSTom Jones * notice, this list of conditions and the following disclaimer in the
17*be9fefafSTom Jones * documentation and/or other materials provided with the distribution.
18*be9fefafSTom Jones *
19*be9fefafSTom Jones * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20*be9fefafSTom Jones * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*be9fefafSTom Jones * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*be9fefafSTom Jones * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23*be9fefafSTom Jones * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*be9fefafSTom Jones * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*be9fefafSTom Jones * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*be9fefafSTom Jones * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*be9fefafSTom Jones * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*be9fefafSTom Jones * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*be9fefafSTom Jones * SUCH DAMAGE.
30*be9fefafSTom Jones */
31*be9fefafSTom Jones
32*be9fefafSTom Jones #include <sys/cdefs.h>
33*be9fefafSTom Jones
34*be9fefafSTom Jones /*
35*be9fefafSTom Jones * Clock Control Module driver for Freescale i.MX 8M SoC family.
36*be9fefafSTom Jones */
37*be9fefafSTom Jones
38*be9fefafSTom Jones #include <sys/param.h>
39*be9fefafSTom Jones #include <sys/systm.h>
40*be9fefafSTom Jones #include <sys/kernel.h>
41*be9fefafSTom Jones #include <sys/module.h>
42*be9fefafSTom Jones #include <sys/mutex.h>
43*be9fefafSTom Jones #include <sys/bus.h>
44*be9fefafSTom Jones #include <sys/rman.h>
45*be9fefafSTom Jones
46*be9fefafSTom Jones #include <dev/ofw/ofw_bus.h>
47*be9fefafSTom Jones #include <dev/ofw/ofw_bus_subr.h>
48*be9fefafSTom Jones
49*be9fefafSTom Jones #include <machine/bus.h>
50*be9fefafSTom Jones
51*be9fefafSTom Jones #include <arm64/freescale/imx/imx_ccm.h>
52*be9fefafSTom Jones #include <arm64/freescale/imx/clk/imx_clk_gate.h>
53*be9fefafSTom Jones #include <arm64/freescale/imx/clk/imx_clk_mux.h>
54*be9fefafSTom Jones #include <arm64/freescale/imx/clk/imx_clk_composite.h>
55*be9fefafSTom Jones #include <arm64/freescale/imx/clk/imx_clk_sscg_pll.h>
56*be9fefafSTom Jones #include <arm64/freescale/imx/clk/imx_clk_frac_pll.h>
57*be9fefafSTom Jones
58*be9fefafSTom Jones #include "clkdev_if.h"
59*be9fefafSTom Jones
60*be9fefafSTom Jones static inline uint32_t
CCU_READ4(struct imx_ccm_softc * sc,bus_size_t off)61*be9fefafSTom Jones CCU_READ4(struct imx_ccm_softc *sc, bus_size_t off)
62*be9fefafSTom Jones {
63*be9fefafSTom Jones
64*be9fefafSTom Jones return (bus_read_4(sc->mem_res, off));
65*be9fefafSTom Jones }
66*be9fefafSTom Jones
67*be9fefafSTom Jones static inline void
CCU_WRITE4(struct imx_ccm_softc * sc,bus_size_t off,uint32_t val)68*be9fefafSTom Jones CCU_WRITE4(struct imx_ccm_softc *sc, bus_size_t off, uint32_t val)
69*be9fefafSTom Jones {
70*be9fefafSTom Jones
71*be9fefafSTom Jones bus_write_4(sc->mem_res, off, val);
72*be9fefafSTom Jones }
73*be9fefafSTom Jones
74*be9fefafSTom Jones int
imx_ccm_detach(device_t dev)75*be9fefafSTom Jones imx_ccm_detach(device_t dev)
76*be9fefafSTom Jones {
77*be9fefafSTom Jones struct imx_ccm_softc *sc;
78*be9fefafSTom Jones
79*be9fefafSTom Jones sc = device_get_softc(dev);
80*be9fefafSTom Jones
81*be9fefafSTom Jones if (sc->mem_res != NULL)
82*be9fefafSTom Jones bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
83*be9fefafSTom Jones
84*be9fefafSTom Jones return (0);
85*be9fefafSTom Jones }
86*be9fefafSTom Jones
87*be9fefafSTom Jones int
imx_ccm_attach(device_t dev)88*be9fefafSTom Jones imx_ccm_attach(device_t dev)
89*be9fefafSTom Jones {
90*be9fefafSTom Jones struct imx_ccm_softc *sc;
91*be9fefafSTom Jones int err, rid;
92*be9fefafSTom Jones phandle_t node;
93*be9fefafSTom Jones int i;
94*be9fefafSTom Jones
95*be9fefafSTom Jones sc = device_get_softc(dev);
96*be9fefafSTom Jones sc->dev = dev;
97*be9fefafSTom Jones err = 0;
98*be9fefafSTom Jones
99*be9fefafSTom Jones /* Allocate bus_space resources. */
100*be9fefafSTom Jones rid = 0;
101*be9fefafSTom Jones sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
102*be9fefafSTom Jones RF_ACTIVE);
103*be9fefafSTom Jones if (sc->mem_res == NULL) {
104*be9fefafSTom Jones device_printf(dev, "Cannot allocate memory resources\n");
105*be9fefafSTom Jones err = ENXIO;
106*be9fefafSTom Jones goto out;
107*be9fefafSTom Jones }
108*be9fefafSTom Jones
109*be9fefafSTom Jones mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
110*be9fefafSTom Jones
111*be9fefafSTom Jones sc->clkdom = clkdom_create(dev);
112*be9fefafSTom Jones if (sc->clkdom == NULL)
113*be9fefafSTom Jones panic("Cannot create clkdom\n");
114*be9fefafSTom Jones
115*be9fefafSTom Jones for (i = 0; i < sc->nclks; i++) {
116*be9fefafSTom Jones switch (sc->clks[i].type) {
117*be9fefafSTom Jones case IMX_CLK_UNDEFINED:
118*be9fefafSTom Jones break;
119*be9fefafSTom Jones case IMX_CLK_LINK:
120*be9fefafSTom Jones clknode_link_register(sc->clkdom,
121*be9fefafSTom Jones sc->clks[i].clk.link);
122*be9fefafSTom Jones break;
123*be9fefafSTom Jones case IMX_CLK_FIXED:
124*be9fefafSTom Jones clknode_fixed_register(sc->clkdom,
125*be9fefafSTom Jones sc->clks[i].clk.fixed);
126*be9fefafSTom Jones break;
127*be9fefafSTom Jones case IMX_CLK_MUX:
128*be9fefafSTom Jones imx_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
129*be9fefafSTom Jones break;
130*be9fefafSTom Jones case IMX_CLK_GATE:
131*be9fefafSTom Jones imx_clk_gate_register(sc->clkdom, sc->clks[i].clk.gate);
132*be9fefafSTom Jones break;
133*be9fefafSTom Jones case IMX_CLK_COMPOSITE:
134*be9fefafSTom Jones imx_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite);
135*be9fefafSTom Jones break;
136*be9fefafSTom Jones case IMX_CLK_SSCG_PLL:
137*be9fefafSTom Jones imx_clk_sscg_pll_register(sc->clkdom, sc->clks[i].clk.sscg_pll);
138*be9fefafSTom Jones break;
139*be9fefafSTom Jones case IMX_CLK_FRAC_PLL:
140*be9fefafSTom Jones imx_clk_frac_pll_register(sc->clkdom, sc->clks[i].clk.frac_pll);
141*be9fefafSTom Jones break;
142*be9fefafSTom Jones case IMX_CLK_DIV:
143*be9fefafSTom Jones clknode_div_register(sc->clkdom, sc->clks[i].clk.div);
144*be9fefafSTom Jones break;
145*be9fefafSTom Jones default:
146*be9fefafSTom Jones device_printf(dev, "Unknown clock type %d\n", sc->clks[i].type);
147*be9fefafSTom Jones return (ENXIO);
148*be9fefafSTom Jones }
149*be9fefafSTom Jones }
150*be9fefafSTom Jones
151*be9fefafSTom Jones if (clkdom_finit(sc->clkdom) != 0)
152*be9fefafSTom Jones panic("cannot finalize clkdom initialization\n");
153*be9fefafSTom Jones
154*be9fefafSTom Jones if (bootverbose)
155*be9fefafSTom Jones clkdom_dump(sc->clkdom);
156*be9fefafSTom Jones
157*be9fefafSTom Jones node = ofw_bus_get_node(dev);
158*be9fefafSTom Jones clk_set_assigned(dev, node);
159*be9fefafSTom Jones
160*be9fefafSTom Jones err = 0;
161*be9fefafSTom Jones
162*be9fefafSTom Jones out:
163*be9fefafSTom Jones
164*be9fefafSTom Jones if (err != 0)
165*be9fefafSTom Jones imx_ccm_detach(dev);
166*be9fefafSTom Jones
167*be9fefafSTom Jones return (err);
168*be9fefafSTom Jones }
169*be9fefafSTom Jones
170*be9fefafSTom Jones static int
imx_ccm_write_4(device_t dev,bus_addr_t addr,uint32_t val)171*be9fefafSTom Jones imx_ccm_write_4(device_t dev, bus_addr_t addr, uint32_t val)
172*be9fefafSTom Jones {
173*be9fefafSTom Jones struct imx_ccm_softc *sc;
174*be9fefafSTom Jones
175*be9fefafSTom Jones sc = device_get_softc(dev);
176*be9fefafSTom Jones CCU_WRITE4(sc, addr, val);
177*be9fefafSTom Jones return (0);
178*be9fefafSTom Jones }
179*be9fefafSTom Jones
180*be9fefafSTom Jones static int
imx_ccm_read_4(device_t dev,bus_addr_t addr,uint32_t * val)181*be9fefafSTom Jones imx_ccm_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
182*be9fefafSTom Jones {
183*be9fefafSTom Jones struct imx_ccm_softc *sc;
184*be9fefafSTom Jones
185*be9fefafSTom Jones sc = device_get_softc(dev);
186*be9fefafSTom Jones
187*be9fefafSTom Jones *val = CCU_READ4(sc, addr);
188*be9fefafSTom Jones return (0);
189*be9fefafSTom Jones }
190*be9fefafSTom Jones
191*be9fefafSTom Jones static int
imx_ccm_modify_4(device_t dev,bus_addr_t addr,uint32_t clr,uint32_t set)192*be9fefafSTom Jones imx_ccm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
193*be9fefafSTom Jones {
194*be9fefafSTom Jones struct imx_ccm_softc *sc;
195*be9fefafSTom Jones uint32_t reg;
196*be9fefafSTom Jones
197*be9fefafSTom Jones sc = device_get_softc(dev);
198*be9fefafSTom Jones
199*be9fefafSTom Jones reg = CCU_READ4(sc, addr);
200*be9fefafSTom Jones reg &= ~clr;
201*be9fefafSTom Jones reg |= set;
202*be9fefafSTom Jones CCU_WRITE4(sc, addr, reg);
203*be9fefafSTom Jones
204*be9fefafSTom Jones return (0);
205*be9fefafSTom Jones }
206*be9fefafSTom Jones
207*be9fefafSTom Jones static void
imx_ccm_device_lock(device_t dev)208*be9fefafSTom Jones imx_ccm_device_lock(device_t dev)
209*be9fefafSTom Jones {
210*be9fefafSTom Jones struct imx_ccm_softc *sc;
211*be9fefafSTom Jones
212*be9fefafSTom Jones sc = device_get_softc(dev);
213*be9fefafSTom Jones mtx_lock(&sc->mtx);
214*be9fefafSTom Jones }
215*be9fefafSTom Jones
216*be9fefafSTom Jones static void
imx_ccm_device_unlock(device_t dev)217*be9fefafSTom Jones imx_ccm_device_unlock(device_t dev)
218*be9fefafSTom Jones {
219*be9fefafSTom Jones struct imx_ccm_softc *sc;
220*be9fefafSTom Jones
221*be9fefafSTom Jones sc = device_get_softc(dev);
222*be9fefafSTom Jones mtx_unlock(&sc->mtx);
223*be9fefafSTom Jones }
224*be9fefafSTom Jones
225*be9fefafSTom Jones static device_method_t imx_ccm_methods[] = {
226*be9fefafSTom Jones /* clkdev interface */
227*be9fefafSTom Jones DEVMETHOD(clkdev_write_4, imx_ccm_write_4),
228*be9fefafSTom Jones DEVMETHOD(clkdev_read_4, imx_ccm_read_4),
229*be9fefafSTom Jones DEVMETHOD(clkdev_modify_4, imx_ccm_modify_4),
230*be9fefafSTom Jones DEVMETHOD(clkdev_device_lock, imx_ccm_device_lock),
231*be9fefafSTom Jones DEVMETHOD(clkdev_device_unlock, imx_ccm_device_unlock),
232*be9fefafSTom Jones
233*be9fefafSTom Jones DEVMETHOD_END
234*be9fefafSTom Jones };
235*be9fefafSTom Jones
236*be9fefafSTom Jones DEFINE_CLASS_0(imx_ccm, imx_ccm_driver, imx_ccm_methods,
237*be9fefafSTom Jones sizeof(struct imx_ccm_softc));
238