Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm64/broadcom/brcmmdio/mdio_nexus_iproc.c
39482 views
1
/*-
2
* Copyright (c) 2019 Juniper Networks, Inc.
3
* Copyright (c) 2019 Semihalf.
4
* All rights reserved.
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
17
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
* POSSIBILITY OF 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/rman.h>
33
#include <sys/systm.h>
34
35
#include <dev/fdt/simplebus.h>
36
#include <dev/ofw/ofw_bus_subr.h>
37
#include <dev/ofw/ofw_bus.h>
38
39
#include <machine/bus.h>
40
#include <machine/resource.h>
41
42
#include "mdio_if.h"
43
44
MALLOC_DEFINE(M_BRCM_IPROC_NEXUS, "Broadcom IPROC MDIO NEXUS",
45
"Broadcom IPROC MDIO NEXUS dynamic memory");
46
47
struct brcm_mdionexus_softc {
48
struct simplebus_softc simplebus_sc;
49
uint32_t mux_id;
50
};
51
52
/* OFW bus interface */
53
struct brcm_mdionexus_ofw_devinfo {
54
struct ofw_bus_devinfo di_dinfo;
55
struct resource_list di_rl;
56
};
57
58
static device_probe_t brcm_mdionexus_fdt_probe;
59
static device_attach_t brcm_mdionexus_fdt_attach;
60
61
static const struct ofw_bus_devinfo * brcm_mdionexus_ofw_get_devinfo(device_t,
62
device_t);
63
static int brcm_mdionexus_mdio_readreg(device_t, int, int);
64
static int brcm_mdionexus_mdio_writereg(device_t, int, int, int);
65
66
static device_method_t brcm_mdionexus_fdt_methods[] = {
67
/* Device interface */
68
DEVMETHOD(device_probe, brcm_mdionexus_fdt_probe),
69
DEVMETHOD(device_attach, brcm_mdionexus_fdt_attach),
70
71
/* Bus interface */
72
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
73
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
74
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
75
76
/* ofw_bus interface */
77
DEVMETHOD(ofw_bus_get_devinfo, brcm_mdionexus_ofw_get_devinfo),
78
DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
79
DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
80
DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
81
DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
82
DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
83
84
/* MDIO interface */
85
/* MDIO interface */
86
DEVMETHOD(mdio_readreg, brcm_mdionexus_mdio_readreg),
87
DEVMETHOD(mdio_writereg, brcm_mdionexus_mdio_writereg),
88
89
DEVMETHOD_END
90
};
91
92
DEFINE_CLASS_0(brcm_mdionexus, brcm_mdionexus_fdt_driver, brcm_mdionexus_fdt_methods,
93
sizeof(struct brcm_mdionexus_softc));
94
95
static driver_t brcm_mdionexus_driver = {
96
"brcm_mdionexus",
97
brcm_mdionexus_fdt_methods,
98
sizeof(struct brcm_mdionexus_softc)
99
};
100
101
EARLY_DRIVER_MODULE(brcm_mdionexus, brcm_iproc_mdio, brcm_mdionexus_driver,
102
NULL, NULL, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
103
104
static int brcm_mdionexus_ofw_bus_attach(device_t);
105
106
static int
107
brcm_mdionexus_mdio_readreg(device_t dev, int phy, int reg)
108
{
109
struct brcm_mdionexus_softc *sc;
110
111
sc = device_get_softc(dev);
112
113
return (MDIO_READREG_MUX(device_get_parent(dev),
114
sc->mux_id, phy, reg));
115
}
116
117
static int
118
brcm_mdionexus_mdio_writereg(device_t dev, int phy, int reg, int val)
119
{
120
struct brcm_mdionexus_softc *sc;
121
122
sc = device_get_softc(dev);
123
124
return (MDIO_WRITEREG_MUX(device_get_parent(dev),
125
sc->mux_id, phy, reg, val));
126
}
127
128
static __inline void
129
get_addr_size_cells(phandle_t node, pcell_t *addr_cells, pcell_t *size_cells)
130
{
131
132
*addr_cells = 2;
133
/* Find address cells if present */
134
OF_getencprop(node, "#address-cells", addr_cells, sizeof(*addr_cells));
135
136
*size_cells = 2;
137
/* Find size cells if present */
138
OF_getencprop(node, "#size-cells", size_cells, sizeof(*size_cells));
139
}
140
141
static int
142
brcm_mdionexus_fdt_probe(device_t dev)
143
{
144
145
if (!ofw_bus_status_okay(dev))
146
return (ENXIO);
147
device_set_desc(dev, "Broadcom MDIO nexus");
148
return (BUS_PROBE_SPECIFIC);
149
}
150
151
static int
152
brcm_mdionexus_fdt_attach(device_t dev)
153
{
154
struct brcm_mdionexus_softc *sc;
155
int err;
156
pcell_t addr_cells, size_cells, buf[2];
157
phandle_t node;
158
159
sc = device_get_softc(dev);
160
161
node = ofw_bus_get_node(dev);
162
get_addr_size_cells(node, &addr_cells, &size_cells);
163
if ((addr_cells != 1) || (size_cells != 0)) {
164
device_printf(dev, "Only addr_cells=1 and size_cells=0 are supported\n");
165
return (EINVAL);
166
}
167
168
if (OF_getencprop(node, "reg", buf, sizeof(pcell_t)) < 0)
169
return (ENXIO);
170
171
sc->mux_id = buf[0];
172
173
err = brcm_mdionexus_ofw_bus_attach(dev);
174
if (err != 0)
175
return (err);
176
177
bus_attach_children(dev);
178
return (0);
179
}
180
181
static const struct ofw_bus_devinfo *
182
brcm_mdionexus_ofw_get_devinfo(device_t bus __unused, device_t child)
183
{
184
struct brcm_mdionexus_ofw_devinfo *di;
185
186
di = device_get_ivars(child);
187
return (&di->di_dinfo);
188
}
189
190
static int
191
brcm_mdionexus_ofw_bus_attach(device_t dev)
192
{
193
struct simplebus_softc *sc;
194
struct brcm_mdionexus_ofw_devinfo *di;
195
device_t child;
196
phandle_t parent, node;
197
198
parent = ofw_bus_get_node(dev);
199
simplebus_init(dev, parent);
200
201
sc = (struct simplebus_softc *)device_get_softc(dev);
202
203
/* Iterate through all bus subordinates */
204
for (node = OF_child(parent); node > 0; node = OF_peer(node)) {
205
/* Allocate and populate devinfo. */
206
di = malloc(sizeof(*di), M_BRCM_IPROC_NEXUS, M_WAITOK | M_ZERO);
207
if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) {
208
free(di, M_BRCM_IPROC_NEXUS);
209
continue;
210
}
211
212
/* Initialize and populate resource list. */
213
resource_list_init(&di->di_rl);
214
ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells,
215
&di->di_rl);
216
ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL);
217
218
/* Add newbus device for this FDT node */
219
child = device_add_child(dev, NULL, DEVICE_UNIT_ANY);
220
if (child == NULL) {
221
resource_list_free(&di->di_rl);
222
ofw_bus_gen_destroy_devinfo(&di->di_dinfo);
223
free(di, M_BRCM_IPROC_NEXUS);
224
continue;
225
}
226
227
device_set_ivars(child, di);
228
}
229
230
return (0);
231
}
232
233