xref: /freebsd-src/sys/dev/qcom_gcc/qcom_gcc_ipq4018.c (revision 1f469a9fc498c3d406ef7c4e347232678f49da0a)
1cd32ac64SAdrian Chadd /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3cd32ac64SAdrian Chadd  *
4cd32ac64SAdrian Chadd  * Copyright (c) 2021, Adrian Chadd <adrian@FreeBSD.org>
5cd32ac64SAdrian Chadd  *
6cd32ac64SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
7cd32ac64SAdrian Chadd  * modification, are permitted provided that the following conditions
8cd32ac64SAdrian Chadd  * are met:
9cd32ac64SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
10cd32ac64SAdrian Chadd  *    notice unmodified, this list of conditions, and the following
11cd32ac64SAdrian Chadd  *    disclaimer.
12cd32ac64SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
13cd32ac64SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
14cd32ac64SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
15cd32ac64SAdrian Chadd  *
16cd32ac64SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17cd32ac64SAdrian Chadd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18cd32ac64SAdrian Chadd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19cd32ac64SAdrian Chadd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20cd32ac64SAdrian Chadd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21cd32ac64SAdrian Chadd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22cd32ac64SAdrian Chadd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23cd32ac64SAdrian Chadd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24cd32ac64SAdrian Chadd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25cd32ac64SAdrian Chadd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26cd32ac64SAdrian Chadd  */
27cd32ac64SAdrian Chadd 
28cd32ac64SAdrian Chadd /* Driver for Qualcomm IPQ4018 clock and reset device */
29cd32ac64SAdrian Chadd 
30cd32ac64SAdrian Chadd #include <sys/param.h>
31cd32ac64SAdrian Chadd #include <sys/kernel.h>
32cd32ac64SAdrian Chadd #include <sys/malloc.h>
33cd32ac64SAdrian Chadd #include <sys/module.h>
34cd32ac64SAdrian Chadd #include <sys/sglist.h>
35cd32ac64SAdrian Chadd #include <sys/random.h>
36cd32ac64SAdrian Chadd #include <sys/stdatomic.h>
37cd32ac64SAdrian Chadd #include <sys/mutex.h>
38cd32ac64SAdrian Chadd 
39cd32ac64SAdrian Chadd #include <machine/bus.h>
40cd32ac64SAdrian Chadd #include <machine/resource.h>
41cd32ac64SAdrian Chadd #include <sys/bus.h>
42cd32ac64SAdrian Chadd 
43cd32ac64SAdrian Chadd #include <dev/fdt/fdt_common.h>
44cd32ac64SAdrian Chadd #include <dev/ofw/ofw_bus.h>
45cd32ac64SAdrian Chadd #include <dev/ofw/ofw_bus_subr.h>
46cd32ac64SAdrian Chadd 
47*1f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
48cd32ac64SAdrian Chadd 
49cd32ac64SAdrian Chadd #include "clkdev_if.h"
50cd32ac64SAdrian Chadd #include "hwreset_if.h"
51cd32ac64SAdrian Chadd 
52cd32ac64SAdrian Chadd #include <dt-bindings/clock/qcom,gcc-ipq4019.h>
53cd32ac64SAdrian Chadd 
54cd32ac64SAdrian Chadd #include "qcom_gcc_ipq4018_var.h"
55cd32ac64SAdrian Chadd 
56cd32ac64SAdrian Chadd 
57cd32ac64SAdrian Chadd static int	qcom_gcc_ipq4018_modevent(module_t, int, void *);
58cd32ac64SAdrian Chadd 
59cd32ac64SAdrian Chadd static int	qcom_gcc_ipq4018_probe(device_t);
60cd32ac64SAdrian Chadd static int	qcom_gcc_ipq4018_attach(device_t);
61cd32ac64SAdrian Chadd static int	qcom_gcc_ipq4018_detach(device_t);
62cd32ac64SAdrian Chadd 
63cd32ac64SAdrian Chadd static int
qcom_gcc_ipq4018_modevent(module_t mod,int type,void * unused)64cd32ac64SAdrian Chadd qcom_gcc_ipq4018_modevent(module_t mod, int type, void *unused)
65cd32ac64SAdrian Chadd {
66cd32ac64SAdrian Chadd 	int error;
67cd32ac64SAdrian Chadd 
68cd32ac64SAdrian Chadd 	switch (type) {
69cd32ac64SAdrian Chadd 	case MOD_LOAD:
70cd32ac64SAdrian Chadd 	case MOD_QUIESCE:
71cd32ac64SAdrian Chadd 	case MOD_UNLOAD:
72cd32ac64SAdrian Chadd 	case MOD_SHUTDOWN:
73cd32ac64SAdrian Chadd 		error = 0;
74cd32ac64SAdrian Chadd 		break;
75cd32ac64SAdrian Chadd 	default:
76cd32ac64SAdrian Chadd 		error = EOPNOTSUPP;
77cd32ac64SAdrian Chadd 		break;
78cd32ac64SAdrian Chadd 	}
79cd32ac64SAdrian Chadd 
80cd32ac64SAdrian Chadd 	return (error);
81cd32ac64SAdrian Chadd }
82cd32ac64SAdrian Chadd 
83cd32ac64SAdrian Chadd static int
qcom_gcc_ipq4018_probe(device_t dev)84cd32ac64SAdrian Chadd qcom_gcc_ipq4018_probe(device_t dev)
85cd32ac64SAdrian Chadd {
86cd32ac64SAdrian Chadd 	if (! ofw_bus_status_okay(dev))
87cd32ac64SAdrian Chadd 		return (ENXIO);
88cd32ac64SAdrian Chadd 
89cd32ac64SAdrian Chadd 	if (ofw_bus_is_compatible(dev, "qcom,gcc-ipq4019") == 0)
90cd32ac64SAdrian Chadd 		return (ENXIO);
91cd32ac64SAdrian Chadd 
92cd32ac64SAdrian Chadd 	return (0);
93cd32ac64SAdrian Chadd }
94cd32ac64SAdrian Chadd 
95cd32ac64SAdrian Chadd static int
qcom_gcc_ipq4018_attach(device_t dev)96cd32ac64SAdrian Chadd qcom_gcc_ipq4018_attach(device_t dev)
97cd32ac64SAdrian Chadd {
98cd32ac64SAdrian Chadd 	struct qcom_gcc_ipq4018_softc *sc;
99cd32ac64SAdrian Chadd 
100cd32ac64SAdrian Chadd 	sc = device_get_softc(dev);
101cd32ac64SAdrian Chadd 
102cd32ac64SAdrian Chadd 	/* Found a compatible device! */
103cd32ac64SAdrian Chadd 	sc->dev = dev;
104cd32ac64SAdrian Chadd 
105cd32ac64SAdrian Chadd 	sc->reg_rid = 0;
106cd32ac64SAdrian Chadd 	sc->reg = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY,
107cd32ac64SAdrian Chadd 	    &sc->reg_rid, 0x60000, RF_ACTIVE);
108cd32ac64SAdrian Chadd 	if (sc->reg == NULL) {
109cd32ac64SAdrian Chadd 		device_printf(dev, "Couldn't allocate memory resource!\n");
110cd32ac64SAdrian Chadd 		return (ENXIO);
111cd32ac64SAdrian Chadd 	}
112cd32ac64SAdrian Chadd 
113cd32ac64SAdrian Chadd 	device_set_desc(dev, "Qualcomm IPQ4018 Clock/Reset Controller");
114cd32ac64SAdrian Chadd 
115cd32ac64SAdrian Chadd 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
116cd32ac64SAdrian Chadd 
117cd32ac64SAdrian Chadd 	/*
118cd32ac64SAdrian Chadd 	 * Register as a reset provider.
119cd32ac64SAdrian Chadd 	 */
120cd32ac64SAdrian Chadd 	hwreset_register_ofw_provider(dev);
121cd32ac64SAdrian Chadd 
122cd32ac64SAdrian Chadd 	/*
123cd32ac64SAdrian Chadd 	 * Setup and register as a clock provider.
124cd32ac64SAdrian Chadd 	 */
125cd32ac64SAdrian Chadd 	qcom_gcc_ipq4018_clock_setup(sc);
126cd32ac64SAdrian Chadd 
127cd32ac64SAdrian Chadd 	return (0);
128cd32ac64SAdrian Chadd }
129cd32ac64SAdrian Chadd 
130cd32ac64SAdrian Chadd static int
qcom_gcc_ipq4018_detach(device_t dev)131cd32ac64SAdrian Chadd qcom_gcc_ipq4018_detach(device_t dev)
132cd32ac64SAdrian Chadd {
133cd32ac64SAdrian Chadd 	struct qcom_gcc_ipq4018_softc *sc;
134cd32ac64SAdrian Chadd 
135cd32ac64SAdrian Chadd 	sc = device_get_softc(dev);
136cd32ac64SAdrian Chadd 
137cd32ac64SAdrian Chadd 	/*
138cd32ac64SAdrian Chadd 	 * TBD - deregistering reset/clock resources.
139cd32ac64SAdrian Chadd 	 */
140cd32ac64SAdrian Chadd 
141cd32ac64SAdrian Chadd 	if (sc->reg != NULL) {
142cd32ac64SAdrian Chadd 		bus_release_resource(sc->dev, SYS_RES_MEMORY,
143cd32ac64SAdrian Chadd 		    sc->reg_rid, sc->reg);
144cd32ac64SAdrian Chadd 	}
145cd32ac64SAdrian Chadd 	return (0);
146cd32ac64SAdrian Chadd }
147cd32ac64SAdrian Chadd 
148cd32ac64SAdrian Chadd static device_method_t qcom_gcc_ipq4018_methods[] = {
149cd32ac64SAdrian Chadd 	/* Device methods. */
150cd32ac64SAdrian Chadd 	DEVMETHOD(device_probe,		qcom_gcc_ipq4018_probe),
151cd32ac64SAdrian Chadd 	DEVMETHOD(device_attach,	qcom_gcc_ipq4018_attach),
152cd32ac64SAdrian Chadd 	DEVMETHOD(device_detach,	qcom_gcc_ipq4018_detach),
153cd32ac64SAdrian Chadd 
154cd32ac64SAdrian Chadd 	/* Reset interface */
155cd32ac64SAdrian Chadd 	DEVMETHOD(hwreset_assert,	qcom_gcc_ipq4018_hwreset_assert),
156cd32ac64SAdrian Chadd 	DEVMETHOD(hwreset_is_asserted,	qcom_gcc_ipq4018_hwreset_is_asserted),
157cd32ac64SAdrian Chadd 
158cd32ac64SAdrian Chadd 	/* Clock interface */
159cd32ac64SAdrian Chadd 	DEVMETHOD(clkdev_read_4,	qcom_gcc_ipq4018_clock_read),
160cd32ac64SAdrian Chadd 	DEVMETHOD(clkdev_write_4,	qcom_gcc_ipq4018_clock_write),
161cd32ac64SAdrian Chadd 	DEVMETHOD(clkdev_modify_4,	qcom_gcc_ipq4018_clock_modify),
162cd32ac64SAdrian Chadd 	DEVMETHOD(clkdev_device_lock,	qcom_gcc_ipq4018_clock_lock),
163cd32ac64SAdrian Chadd 	DEVMETHOD(clkdev_device_unlock,	qcom_gcc_ipq4018_clock_unlock),
164cd32ac64SAdrian Chadd 
165cd32ac64SAdrian Chadd 	DEVMETHOD_END
166cd32ac64SAdrian Chadd };
167cd32ac64SAdrian Chadd 
168cd32ac64SAdrian Chadd static driver_t qcom_gcc_ipq4018_driver = {
169cd32ac64SAdrian Chadd 	"qcom_gcc",
170cd32ac64SAdrian Chadd 	qcom_gcc_ipq4018_methods,
171cd32ac64SAdrian Chadd 	sizeof(struct qcom_gcc_ipq4018_softc)
172cd32ac64SAdrian Chadd };
173cd32ac64SAdrian Chadd 
174cd32ac64SAdrian Chadd EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, simplebus, qcom_gcc_ipq4018_driver,
17553e1cbefSJohn Baldwin     qcom_gcc_ipq4018_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
176cd32ac64SAdrian Chadd EARLY_DRIVER_MODULE(qcom_gcc_ipq4018, ofwbus, qcom_gcc_ipq4018_driver,
17753e1cbefSJohn Baldwin     qcom_gcc_ipq4018_modevent, NULL, BUS_PASS_CPU + BUS_PASS_ORDER_EARLY);
178cd32ac64SAdrian Chadd MODULE_VERSION(qcom_gcc_ipq4018, 1);
179