Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/ti/clk/ti_gate_clock.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2020 Oskar Holmlund <[email protected]>
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 ``AS IS'' AND ANY EXPRESS OR
16
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
* 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/conf.h>
30
#include <sys/bus.h>
31
#include <sys/kernel.h>
32
#include <sys/module.h>
33
#include <sys/systm.h>
34
#include <sys/libkern.h>
35
36
#include <machine/bus.h>
37
#include <dev/fdt/simplebus.h>
38
39
#include <dev/clk/clk_gate.h>
40
#include <dev/ofw/ofw_bus.h>
41
#include <dev/ofw/ofw_bus_subr.h>
42
43
#include "clock_common.h"
44
45
#define DEBUG_GATE 0
46
47
#if DEBUG_GATE
48
#define DPRINTF(dev, msg...) device_printf(dev, msg)
49
#else
50
#define DPRINTF(dev, msg...)
51
#endif
52
53
/*
54
* Devicetree description
55
* Documentation/devicetree/bindings/clock/ti/gate.txt
56
*/
57
58
struct ti_gate_softc {
59
device_t sc_dev;
60
bool attach_done;
61
uint8_t sc_type;
62
63
struct clk_gate_def gate_def;
64
struct clock_cell_info clock_cell;
65
struct clkdom *clkdom;
66
};
67
68
static int ti_gate_probe(device_t dev);
69
static int ti_gate_attach(device_t dev);
70
static int ti_gate_detach(device_t dev);
71
72
#define TI_GATE_CLOCK 7
73
#define TI_WAIT_GATE_CLOCK 6
74
#define TI_DSS_GATE_CLOCK 5
75
#define TI_AM35XX_GATE_CLOCK 4
76
#define TI_CLKDM_GATE_CLOCK 3
77
#define TI_HSDIV_GATE_CLOCK 2
78
#define TI_COMPOSITE_NO_WAIT_GATE_CLOCK 1
79
#define TI_GATE_END 0
80
81
static struct ofw_compat_data compat_data[] = {
82
{ "ti,gate-clock", TI_GATE_CLOCK },
83
{ "ti,wait-gate-clock", TI_WAIT_GATE_CLOCK },
84
{ "ti,dss-gate-clock", TI_DSS_GATE_CLOCK },
85
{ "ti,am35xx-gate-clock", TI_AM35XX_GATE_CLOCK },
86
{ "ti,clkdm-gate-clock", TI_CLKDM_GATE_CLOCK },
87
{ "ti,hsdiv-gate-cloc", TI_HSDIV_GATE_CLOCK },
88
{ "ti,composite-no-wait-gate-clock", TI_COMPOSITE_NO_WAIT_GATE_CLOCK },
89
{ NULL, TI_GATE_END }
90
};
91
92
static int
93
ti_gate_probe(device_t dev)
94
{
95
if (!ofw_bus_status_okay(dev))
96
return (ENXIO);
97
98
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
99
return (ENXIO);
100
101
device_set_desc(dev, "TI Gate Clock");
102
103
return (BUS_PROBE_DEFAULT);
104
}
105
106
static int
107
register_clk(struct ti_gate_softc *sc) {
108
int err;
109
sc->clkdom = clkdom_create(sc->sc_dev);
110
if (sc->clkdom == NULL) {
111
DPRINTF(sc->sc_dev, "Failed to create clkdom\n");
112
return ENXIO;
113
}
114
115
err = clknode_gate_register(sc->clkdom, &sc->gate_def);
116
if (err) {
117
DPRINTF(sc->sc_dev, "clknode_gate_register failed %x\n", err);
118
return ENXIO;
119
}
120
121
err = clkdom_finit(sc->clkdom);
122
if (err) {
123
DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err);
124
return ENXIO;
125
}
126
127
return (0);
128
}
129
130
static int
131
ti_gate_attach(device_t dev)
132
{
133
struct ti_gate_softc *sc;
134
phandle_t node;
135
int err;
136
cell_t value;
137
138
sc = device_get_softc(dev);
139
sc->sc_dev = dev;
140
node = ofw_bus_get_node(dev);
141
142
/* Get the compatible type */
143
sc->sc_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
144
145
/* Get the content of reg properties */
146
if (sc->sc_type != TI_CLKDM_GATE_CLOCK) {
147
OF_getencprop(node, "reg", &value, sizeof(value));
148
sc->gate_def.offset = value;
149
}
150
#if DEBUG_GATE
151
else {
152
DPRINTF(sc->sc_dev, "no reg (TI_CLKDM_GATE_CLOCK)\n");
153
}
154
#endif
155
156
if (OF_hasprop(node, "ti,bit-shift")) {
157
OF_getencprop(node, "ti,bit-shift", &value, sizeof(value));
158
sc->gate_def.shift = value;
159
DPRINTF(sc->sc_dev, "ti,bit-shift => shift %x\n", sc->gate_def.shift);
160
}
161
if (OF_hasprop(node, "ti,set-bit-to-disable")) {
162
sc->gate_def.on_value = 0;
163
sc->gate_def.off_value = 1;
164
DPRINTF(sc->sc_dev,
165
"on_value = 0, off_value = 1 (ti,set-bit-to-disable)\n");
166
} else {
167
sc->gate_def.on_value = 1;
168
sc->gate_def.off_value = 0;
169
DPRINTF(sc->sc_dev, "on_value = 1, off_value = 0\n");
170
}
171
172
sc->gate_def.gate_flags = 0x0;
173
174
read_clock_cells(sc->sc_dev, &sc->clock_cell);
175
176
create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef);
177
178
/* Calculate mask */
179
sc->gate_def.mask = (1 << fls(sc->clock_cell.num_real_clocks)) - 1;
180
DPRINTF(sc->sc_dev, "num_real_clocks %x gate_def.mask %x\n",
181
sc->clock_cell.num_real_clocks, sc->gate_def.mask);
182
183
err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef);
184
185
if (err) {
186
/* free_clkdef will be called in ti_gate_new_pass */
187
DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n");
188
bus_attach_children(sc->dev);
189
return (0);
190
}
191
192
err = register_clk(sc);
193
194
if (err) {
195
/* free_clkdef will be called in ti_gate_new_pass */
196
DPRINTF(sc->sc_dev, "register_clk failed\n");
197
bus_attach_children(sc->dev);
198
return (0);
199
}
200
201
sc->attach_done = true;
202
203
free_clkdef(&sc->gate_def.clkdef);
204
205
bus_attach_children(sc->dev);
206
return (0);
207
}
208
209
static int
210
ti_gate_detach(device_t dev)
211
{
212
return (EBUSY);
213
}
214
215
static void
216
ti_gate_new_pass(device_t dev) {
217
struct ti_gate_softc *sc;
218
int err;
219
220
sc = device_get_softc(dev);
221
222
if (sc->attach_done) {
223
return;
224
}
225
226
err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef);
227
if (err) {
228
/* free_clkdef will be called in later call to ti_gate_new_pass */
229
DPRINTF(sc->sc_dev, "new_pass find_parent_clock_names failed\n");
230
return;
231
}
232
233
err = register_clk(sc);
234
if (err) {
235
/* free_clkdef will be called in later call to ti_gate_new_pass */
236
DPRINTF(sc->sc_dev, "new_pass register_clk failed\n");
237
return;
238
}
239
240
sc->attach_done = true;
241
242
free_clkdef(&sc->gate_def.clkdef);
243
}
244
245
static device_method_t ti_gate_methods[] = {
246
/* Device interface */
247
DEVMETHOD(device_probe, ti_gate_probe),
248
DEVMETHOD(device_attach, ti_gate_attach),
249
DEVMETHOD(device_detach, ti_gate_detach),
250
251
/* Bus interface */
252
DEVMETHOD(bus_new_pass, ti_gate_new_pass),
253
254
DEVMETHOD_END
255
};
256
257
DEFINE_CLASS_0(ti_gate, ti_gate_driver, ti_gate_methods,
258
sizeof(struct ti_gate_softc));
259
260
EARLY_DRIVER_MODULE(ti_gate, simplebus, ti_gate_driver, 0, 0,
261
BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
262
MODULE_VERSION(ti_gate, 1);
263
264