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