Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/mv/mv_ap806_clock.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2018 Rubicon Communications, LLC (Netgate)
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/systm.h>
30
#include <sys/bus.h>
31
32
#include <sys/kernel.h>
33
#include <sys/module.h>
34
#include <sys/rman.h>
35
#include <sys/lock.h>
36
#include <sys/mutex.h>
37
38
#include <machine/bus.h>
39
#include <machine/resource.h>
40
#include <machine/intr.h>
41
42
#include <dev/clk/clk_fixed.h>
43
#include <dev/syscon/syscon.h>
44
45
#include <dev/ofw/ofw_bus.h>
46
#include <dev/ofw/ofw_bus_subr.h>
47
48
#include "syscon_if.h"
49
50
static struct clk_fixed_def ap806_clk_cluster_0 = {
51
.clkdef.id = 0,
52
.clkdef.name = "ap806-cpu-cluster-0",
53
.freq = 0,
54
};
55
56
static struct clk_fixed_def ap806_clk_cluster_1 = {
57
.clkdef.id = 1,
58
.clkdef.name = "ap806-cpu-cluster-1",
59
.freq = 0,
60
};
61
62
static struct clk_fixed_def ap806_clk_fixed = {
63
.clkdef.id = 2,
64
.clkdef.name = "ap806-fixed",
65
.freq = 1200000000,
66
};
67
68
/* Thoses are the only exported clocks AFAICT */
69
70
static const char *mss_parents[] = {"ap806-fixed"};
71
static struct clk_fixed_def ap806_clk_mss = {
72
.clkdef.id = 3,
73
.clkdef.name = "ap806-mss",
74
.clkdef.parent_names = mss_parents,
75
.clkdef.parent_cnt = 1,
76
.mult = 1,
77
.div = 6,
78
};
79
80
static const char *sdio_parents[] = {"ap806-fixed"};
81
static struct clk_fixed_def ap806_clk_sdio = {
82
.clkdef.id = 4,
83
.clkdef.name = "ap806-sdio",
84
.clkdef.parent_names = sdio_parents,
85
.clkdef.parent_cnt = 1,
86
.mult = 1,
87
.div = 3,
88
};
89
90
struct mv_ap806_clock_softc {
91
device_t dev;
92
struct syscon *syscon;
93
};
94
95
static struct ofw_compat_data compat_data[] = {
96
{"marvell,ap806-clock", 1},
97
{NULL, 0}
98
};
99
100
#define RD4(sc, reg) SYSCON_READ_4((sc)->syscon, (reg))
101
#define WR4(sc, reg, val) SYSCON_WRITE_4((sc)->syscon, (reg), (val))
102
103
static int
104
mv_ap806_clock_probe(device_t dev)
105
{
106
107
if (!ofw_bus_status_okay(dev))
108
return (ENXIO);
109
110
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
111
return (ENXIO);
112
113
device_set_desc(dev, "Marvell AP806 Clock Controller");
114
return (BUS_PROBE_DEFAULT);
115
}
116
117
static int
118
mv_ap806_clock_attach(device_t dev)
119
{
120
struct mv_ap806_clock_softc *sc;
121
struct clkdom *clkdom;
122
uint64_t clock_freq;
123
uint32_t reg;
124
125
sc = device_get_softc(dev);
126
sc->dev = dev;
127
128
if (SYSCON_GET_HANDLE(sc->dev, &sc->syscon) != 0 ||
129
sc->syscon == NULL) {
130
device_printf(dev, "cannot get syscon for device\n");
131
return (ENXIO);
132
}
133
134
reg = RD4(sc, 0x400);
135
switch (reg & 0x1f) {
136
case 0x0:
137
case 0x1:
138
clock_freq = 2000000000;
139
break;
140
case 0x4:
141
clock_freq = 1600000000;
142
break;
143
case 0x6:
144
clock_freq = 1800000000;
145
break;
146
case 0x7:
147
clock_freq = 1800000000;
148
break;
149
case 0xb:
150
clock_freq = 1600000000;
151
break;
152
case 0xd:
153
clock_freq = 1600000000;
154
break;
155
case 0x13:
156
clock_freq = 1000000000;
157
break;
158
case 0x14:
159
clock_freq = 1333000000;
160
break;
161
case 0x17:
162
clock_freq = 1333000000;
163
break;
164
case 0x19:
165
clock_freq = 1200000000;
166
break;
167
case 0x1a:
168
clock_freq = 1400000000;
169
break;
170
case 0x1b:
171
clock_freq = 600000000;
172
break;
173
case 0x1c:
174
clock_freq = 800000000;
175
break;
176
case 0x1d:
177
clock_freq = 1000000000;
178
break;
179
default:
180
device_printf(dev, "Cannot guess clock freq with reg %x\n",
181
reg & 0x1f);
182
return (ENXIO);
183
break;
184
};
185
186
ap806_clk_cluster_0.freq = clock_freq;
187
ap806_clk_cluster_1.freq = clock_freq;
188
clkdom = clkdom_create(dev);
189
190
clknode_fixed_register(clkdom, &ap806_clk_cluster_0);
191
clknode_fixed_register(clkdom, &ap806_clk_cluster_1);
192
clknode_fixed_register(clkdom, &ap806_clk_fixed);
193
clknode_fixed_register(clkdom, &ap806_clk_mss);
194
clknode_fixed_register(clkdom, &ap806_clk_sdio);
195
196
clkdom_finit(clkdom);
197
198
if (bootverbose)
199
clkdom_dump(clkdom);
200
return (0);
201
}
202
203
static int
204
mv_ap806_clock_detach(device_t dev)
205
{
206
207
return (EBUSY);
208
}
209
210
static device_method_t mv_ap806_clock_methods[] = {
211
/* Device interface */
212
DEVMETHOD(device_probe, mv_ap806_clock_probe),
213
DEVMETHOD(device_attach, mv_ap806_clock_attach),
214
DEVMETHOD(device_detach, mv_ap806_clock_detach),
215
216
DEVMETHOD_END
217
};
218
219
static driver_t mv_ap806_clock_driver = {
220
"mv_ap806_clock",
221
mv_ap806_clock_methods,
222
sizeof(struct mv_ap806_clock_softc),
223
};
224
225
EARLY_DRIVER_MODULE(mv_ap806_clock, simplebus, mv_ap806_clock_driver, 0, 0,
226
BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE);
227
228