xref: /freebsd/sys/arm64/freescale/imx/imx_ccm.c (revision be9fefafc2801ef449a0f3205c9397ba35425323)
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