1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Semihalf.
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 AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, 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 
28 #include <sys/cdefs.h>
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/mutex.h>
34 #include <sys/rman.h>
35 #include <machine/bus.h>
36 
37 #include <dev/fdt/simplebus.h>
38 
39 #include <dev/extres/clk/clk.h>
40 #include <dev/extres/clk/clk_fixed.h>
41 
42 #include <dev/ofw/ofw_bus.h>
43 #include <dev/ofw/ofw_bus_subr.h>
44 
45 #include "clkdev_if.h"
46 #include "periph.h"
47 
48 #define TBG_COUNT 4
49 #define XTAL_OFW_INDEX 4
50 
51 static struct resource_spec a37x0_periph_clk_spec[] = {
52 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
53 	{ -1, 0 }
54 };
55 
56 int
57 a37x0_periph_clk_attach(device_t dev)
58 {
59 	struct a37x0_periph_clknode_def *dev_defs;
60 	struct a37x0_periph_clk_softc *sc;
61 	const char *tbg_clocks[5];
62 	const char *xtal_clock;
63 	phandle_t node;
64 	int error, i;
65 	clk_t clock;
66 
67 	sc = device_get_softc(dev);
68 	node = ofw_bus_get_node(dev);
69 	sc->dev = dev;
70 
71 	mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
72 
73 	if (bus_alloc_resources(dev, a37x0_periph_clk_spec, &sc->res) != 0) {
74 		device_printf(dev, "Cannot allocate resources\n");
75 		return (ENXIO);
76 	}
77 
78 	sc->clkdom = clkdom_create(dev);
79 	if (sc->clkdom == NULL) {
80 		device_printf(dev, "Cannot create clock domain\n");
81 		return (ENXIO);
82 	}
83 
84 	for (i = 0; i < TBG_COUNT; i++){
85 		error = clk_get_by_ofw_index(dev, node, i, &clock);
86 		if (error)
87 			goto fail;
88 		tbg_clocks[i] = clk_get_name(clock);
89 	}
90 
91 	error = clk_get_by_ofw_index(dev, node, XTAL_OFW_INDEX, &clock);
92 	if (error)
93 		goto fail;
94 	xtal_clock = clk_get_name(clock);
95 
96 	dev_defs = sc->devices;
97 
98 	for (i = 0; i< sc->device_count; i++) {
99 		dev_defs[i].common_def.tbgs = tbg_clocks;
100 		dev_defs[i].common_def.xtal = xtal_clock;
101 		dev_defs[i].common_def.tbg_cnt = TBG_COUNT;
102 		switch (dev_defs[i].type) {
103 		case CLK_FULL_DD:
104 			error = a37x0_periph_d_register_full_clk_dd(
105 			    sc->clkdom, &dev_defs[i]);
106 			if (error)
107 				goto fail;
108 			break;
109 
110 		case CLK_FULL:
111 			error = a37x0_periph_d_register_full_clk(
112 			    sc->clkdom, &dev_defs[i]);
113 			if (error)
114 				goto fail;
115 			break;
116 
117 		case CLK_GATE:
118 			error = a37x0_periph_gate_register_gate(
119 			    sc->clkdom, &dev_defs[i]);
120 			if (error)
121 				goto fail;
122 			break;
123 
124 		case CLK_MUX_GATE:
125 			error = a37x0_periph_register_mux_gate(
126 			   sc->clkdom, &dev_defs[i]);
127 			if (error)
128 				goto fail;
129 			break;
130 
131 		case CLK_FIXED:
132 			error = a37x0_periph_fixed_register_fixed(
133 			   sc->clkdom, &dev_defs[i]);
134 			if (error)
135 				goto fail;
136 			break;
137 
138 		case CLK_CPU:
139 			error = a37x0_periph_d_register_periph_cpu(
140 			   sc->clkdom, &dev_defs[i]);
141 			if (error)
142 				goto fail;
143 			break;
144 
145 		case CLK_MDD:
146 			error = a37x0_periph_d_register_mdd(
147 			    sc->clkdom, &dev_defs[i]);
148 			if (error)
149 				goto fail;
150 			break;
151 
152 		case CLK_MUX_GATE_FIXED:
153 			error = a37x0_periph_register_mux_gate_fixed(
154 			    sc->clkdom, &dev_defs[i]);
155 			if (error)
156 				goto fail;
157 			break;
158 
159 		default:
160 			return (ENXIO);
161 		}
162 	}
163 
164 	error = clkdom_finit(sc->clkdom);
165 	if (error)
166 		goto fail;
167 
168 	if (bootverbose)
169 		clkdom_dump(sc->clkdom);
170 
171 	return (0);
172 
173 fail:
174 	bus_release_resources(dev, a37x0_periph_clk_spec, &sc->res);
175 
176 	return (error);
177 
178 }
179 
180 int
181 a37x0_periph_clk_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
182 {
183 	struct a37x0_periph_clk_softc *sc;
184 
185 	sc = device_get_softc(dev);
186 	*val = bus_read_4(sc->res, addr);
187 
188 	return (0);
189 }
190 
191 void
192 a37x0_periph_clk_device_lock(device_t dev)
193 {
194 	struct a37x0_periph_clk_softc *sc;
195 
196 	sc = device_get_softc(dev);
197 	mtx_lock(&sc->mtx);
198 }
199 
200 void
201 a37x0_periph_clk_device_unlock(device_t dev)
202 {
203 	struct a37x0_periph_clk_softc *sc;
204 
205 	sc = device_get_softc(dev);
206 	mtx_unlock(&sc->mtx);
207 }
208 
209 int
210 a37x0_periph_clk_detach(device_t dev)
211 {
212 
213 	return (EBUSY);
214 }
215