xref: /freebsd/sys/dev/dpaa2/memac_mdio_acpi.c (revision 22cf89c938886d14f5796fc49f9f020c23ea8eaf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright © 2021-2022 Bjoern A. Zeeb
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/kernel.h>
31 #include <sys/bus.h>
32 #include <sys/rman.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/endian.h>
36 #include <sys/socket.h>
37 
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 
41 #include <contrib/dev/acpica/include/acpi.h>
42 #include <dev/acpica/acpivar.h>
43 
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/if_media.h>
47 
48 #include <dev/mii/mii.h>
49 #include <dev/mii/miivar.h>
50 
51 #include "memac_mdio.h"
52 #include "memac_mdio_if.h"
53 #include "acpi_bus_if.h"
54 #include "miibus_if.h"
55 
56 /* -------------------------------------------------------------------------- */
57 
58 struct memacphy_softc_acpi {
59 	struct memacphy_softc_common	scc;
60 	int				uid;
61 	uint64_t			phy_channel;
62 	char				compatible[64];
63 };
64 
65 static void
66 memacphy_acpi_miibus_statchg(device_t dev)
67 {
68 	struct memacphy_softc_acpi *sc;
69 
70 	sc = device_get_softc(dev);
71 	memacphy_miibus_statchg(&sc->scc);
72 }
73 
74 static int
75 memacphy_acpi_set_ni_dev(device_t dev, device_t nidev)
76 {
77 	struct memacphy_softc_acpi *sc;
78 
79 	sc = device_get_softc(dev);
80 	return (memacphy_set_ni_dev(&sc->scc, nidev));
81 }
82 
83 static int
84 memacphy_acpi_get_phy_loc(device_t dev, int *phy_loc)
85 {
86 	struct memacphy_softc_acpi *sc;
87 
88 	sc = device_get_softc(dev);
89 	return (memacphy_get_phy_loc(&sc->scc, phy_loc));
90 }
91 
92 static int
93 memacphy_acpi_probe(device_t dev)
94 {
95 
96 	device_set_desc(dev, "MEMAC PHY (acpi)");
97 	return (BUS_PROBE_DEFAULT);
98 }
99 
100 static int
101 memacphy_acpi_attach(device_t dev)
102 {
103 	struct memacphy_softc_acpi *sc;
104 	ACPI_HANDLE h;
105 	ssize_t s;
106 
107 	sc = device_get_softc(dev);
108 	sc->scc.dev = dev;
109 	h = acpi_get_handle(dev);
110 
111 	s = acpi_GetInteger(h, "_UID", &sc->uid);
112 	if (ACPI_FAILURE(s)) {
113 		device_printf(dev, "Cannot get '_UID' property: %zd\n", s);
114 		return (ENXIO);
115 	}
116 
117 	s = device_get_property(dev, "phy-channel",
118 	    &sc->phy_channel, sizeof(sc->phy_channel), DEVICE_PROP_UINT64);
119 	if (s != -1)
120 		sc->scc.phy = sc->phy_channel;
121 	else
122 		sc->scc.phy = -1;
123 	s = device_get_property(dev, "compatible",
124 	    sc->compatible, sizeof(sc->compatible), DEVICE_PROP_ANY);
125 
126 	if (bootverbose)
127 		device_printf(dev, "UID %#04x phy-channel %ju compatible '%s' phy %u\n",
128 		    sc->uid, sc->phy_channel,
129 		    sc->compatible[0] != '\0' ? sc->compatible : "", sc->scc.phy);
130 
131 	if (sc->scc.phy == -1)
132 		return (ENXIO);
133 	return (0);
134 }
135 
136 static device_method_t memacphy_acpi_methods[] = {
137 	/* Device interface */
138 	DEVMETHOD(device_probe,		memacphy_acpi_probe),
139 	DEVMETHOD(device_attach,	memacphy_acpi_attach),
140 	DEVMETHOD(device_detach,	bus_generic_detach),
141 
142 	/* MII interface */
143 	DEVMETHOD(miibus_readreg,	memacphy_miibus_readreg),
144 	DEVMETHOD(miibus_writereg,	memacphy_miibus_writereg),
145 	DEVMETHOD(miibus_statchg,	memacphy_acpi_miibus_statchg),
146 
147 	/* memac */
148 	DEVMETHOD(memac_mdio_set_ni_dev, memacphy_acpi_set_ni_dev),
149 	DEVMETHOD(memac_mdio_get_phy_loc, memacphy_acpi_get_phy_loc),
150 
151 	DEVMETHOD_END
152 };
153 
154 DEFINE_CLASS_0(memacphy_acpi, memacphy_acpi_driver, memacphy_acpi_methods,
155     sizeof(struct memacphy_softc_acpi));
156 
157 EARLY_DRIVER_MODULE(memacphy_acpi, memac_mdio_acpi, memacphy_acpi_driver, 0, 0,
158     BUS_PASS_SUPPORTDEV);
159 DRIVER_MODULE(miibus, memacphy_acpi, miibus_driver, 0, 0);
160 MODULE_DEPEND(memacphy_acpi, miibus, 1, 1, 1);
161 
162 /* -------------------------------------------------------------------------- */
163 
164 struct memac_mdio_softc_acpi {
165 	struct memac_mdio_softc_common	scc;
166 };
167 
168 static int
169 memac_acpi_miibus_readreg(device_t dev, int phy, int reg)
170 {
171 	struct memac_mdio_softc_acpi *sc;
172 
173 	sc = device_get_softc(dev);
174 	return (memac_miibus_readreg(&sc->scc, phy, reg));
175 }
176 
177 static int
178 memac_acpi_miibus_writereg(device_t dev, int phy, int reg, int data)
179 {
180 	struct memac_mdio_softc_acpi *sc;
181 
182 	sc = device_get_softc(dev);
183 	return (memac_miibus_writereg(&sc->scc, phy, reg, data));
184 }
185 
186 /* Context for walking PHY child devices. */
187 struct memac_mdio_walk_ctx {
188 	device_t	dev;
189 	int		count;
190 	int		countok;
191 };
192 
193 static char *memac_mdio_ids[] = {
194 	"NXP0006",
195 	NULL
196 };
197 
198 static int
199 memac_mdio_acpi_probe(device_t dev)
200 {
201 	int rc;
202 
203 	if (acpi_disabled("fsl_memac_mdio"))
204 		return (ENXIO);
205 
206 	rc = ACPI_ID_PROBE(device_get_parent(dev), dev, memac_mdio_ids, NULL);
207 	if (rc <= 0)
208 		device_set_desc(dev, "Freescale XGMAC MDIO Bus");
209 
210 	return (rc);
211 }
212 
213 static ACPI_STATUS
214 memac_mdio_acpi_probe_child(ACPI_HANDLE h, device_t *dev, int level, void *arg)
215 {
216 	struct memac_mdio_walk_ctx *ctx;
217 	struct acpi_device *ad;
218 	device_t child;
219 	uint32_t adr;
220 
221 	ctx = (struct memac_mdio_walk_ctx *)arg;
222 	ctx->count++;
223 
224 	if (ACPI_FAILURE(acpi_GetInteger(h, "_ADR", &adr)))
225 		return (AE_OK);
226 
227 	/* Technically M_ACPIDEV */
228 	if ((ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL)
229 		return (AE_OK);
230 
231 	child = device_add_child(ctx->dev, "memacphy_acpi", -1);
232 	if (child == NULL) {
233 		free(ad, M_DEVBUF);
234 		return (AE_OK);
235 	}
236 	ad->ad_handle = h;
237 	ad->ad_cls_class = 0xffffff;
238 	resource_list_init(&ad->ad_rl);
239 	device_set_ivars(child, ad);
240 	*dev = child;
241 
242 	ctx->countok++;
243 	return (AE_OK);
244 }
245 
246 static int
247 memac_mdio_acpi_attach(device_t dev)
248 {
249 	struct memac_mdio_softc_acpi *sc;
250 	struct memac_mdio_walk_ctx ctx;
251 	int error;
252 
253 	sc = device_get_softc(dev);
254 	sc->scc.dev = dev;
255 
256 	error = memac_mdio_generic_attach(&sc->scc);
257 	if (error != 0)
258 		return (error);
259 
260 	ctx.dev = dev;
261 	ctx.count = 0;
262 	ctx.countok = 0;
263 	ACPI_SCAN_CHILDREN(device_get_parent(dev), dev, 1,
264 	    memac_mdio_acpi_probe_child, &ctx);
265 	if (ctx.countok > 0) {
266 		bus_generic_probe(dev);
267 		bus_generic_attach(dev);
268 	}
269 
270 	return (0);
271 }
272 
273 static int
274 memac_mdio_acpi_detach(device_t dev)
275 {
276 	struct memac_mdio_softc_acpi *sc;
277 
278 	sc = device_get_softc(dev);
279 	return (memac_mdio_generic_detach(&sc->scc));
280 }
281 
282 static device_method_t memac_mdio_acpi_methods[] = {
283 	/* Device interface */
284 	DEVMETHOD(device_probe,		memac_mdio_acpi_probe),
285 	DEVMETHOD(device_attach,	memac_mdio_acpi_attach),
286 	DEVMETHOD(device_detach,	memac_mdio_acpi_detach),
287 
288 	/* MII interface */
289 	DEVMETHOD(miibus_readreg,	memac_acpi_miibus_readreg),
290 	DEVMETHOD(miibus_writereg,	memac_acpi_miibus_writereg),
291 
292 	/* .. */
293 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
294 	DEVMETHOD(bus_read_ivar,	memac_mdio_read_ivar),
295 	DEVMETHOD(bus_get_property,	memac_mdio_get_property),
296 
297 	DEVMETHOD_END
298 };
299 
300 DEFINE_CLASS_0(memac_mdio_acpi, memac_mdio_acpi_driver, memac_mdio_acpi_methods,
301     sizeof(struct memac_mdio_softc_acpi));
302 
303 EARLY_DRIVER_MODULE(memac_mdio_acpi, acpi, memac_mdio_acpi_driver, 0, 0,
304     BUS_PASS_SUPPORTDEV);
305 
306 DRIVER_MODULE(miibus, memac_mdio_acpi, miibus_driver, 0, 0);
307 MODULE_DEPEND(memac_mdio_acpi, miibus, 1, 1, 1);
308 MODULE_VERSION(memac_mdio_acpi, 1);
309