xref: /openbsd/sys/dev/fdt/mvmdio.c (revision 097a140d)
1 /*	$OpenBSD: mvmdio.c,v 1.3 2020/11/28 20:06:05 kettenis Exp $	*/
2 /*	$NetBSD: if_mvneta.c,v 1.41 2015/04/15 10:15:40 hsuenaga Exp $	*/
3 /*
4  * Copyright (c) 2007, 2008, 2013 KIYOHARA Takashi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/socket.h>
33 #include <sys/sockio.h>
34 #include <sys/mutex.h>
35 
36 #include <machine/bus.h>
37 #include <machine/fdt.h>
38 
39 #ifdef __armv7__
40 #include <arm/simplebus/simplebusvar.h>
41 #else
42 #include <arm64/dev/simplebusvar.h>
43 #endif
44 
45 #include <dev/ofw/openfirm.h>
46 #include <dev/ofw/ofw_clock.h>
47 #include <dev/ofw/ofw_pinctrl.h>
48 #include <dev/ofw/ofw_misc.h>
49 #include <dev/ofw/fdt.h>
50 
51 #include <dev/fdt/if_mvnetareg.h>
52 
53 #include <net/if.h>
54 
55 #define MVNETA_READ(sc, reg) \
56 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
57 #define MVNETA_WRITE(sc, reg, val) \
58 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
59 
60 struct mvmdio_softc {
61 	struct simplebus_softc sc_sbus;
62 
63 	bus_space_tag_t sc_iot;
64 	bus_space_handle_t sc_ioh;
65 
66 	struct mutex sc_mtx;
67 	struct mii_bus sc_mii;
68 };
69 
70 static int mvmdio_match(struct device *, void *, void *);
71 static void mvmdio_attach(struct device *, struct device *, void *);
72 
73 int mvmdio_smi_readreg(struct device *, int, int);
74 void mvmdio_smi_writereg(struct device *, int, int, int);
75 
76 struct cfdriver mvmdio_cd = {
77 	NULL, "mvmdio", DV_DULL
78 };
79 
80 struct cfattach mvmdio_ca = {
81 	sizeof (struct mvmdio_softc), mvmdio_match, mvmdio_attach,
82 };
83 
84 static int
85 mvmdio_match(struct device *parent, void *cfdata, void *aux)
86 {
87 	struct fdt_attach_args *faa = aux;
88 
89 	return OF_is_compatible(faa->fa_node, "marvell,orion-mdio");
90 }
91 
92 static void
93 mvmdio_attach(struct device *parent, struct device *self, void *aux)
94 {
95 	struct mvmdio_softc *sc = (struct mvmdio_softc *) self;
96 	struct fdt_attach_args *faa = aux;
97 
98 	if (faa->fa_nreg < 1) {
99 		printf(": no registers\n");
100 		return;
101 	}
102 
103 	sc->sc_iot = faa->fa_iot;
104 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
105 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
106 		printf(": can't map registers\n");
107 		return;
108 	}
109 
110 	pinctrl_byname(faa->fa_node, "default");
111 	clock_enable_all(faa->fa_node);
112 
113 	mtx_init(&sc->sc_mtx, IPL_NET);
114 
115 	sc->sc_mii.md_node = faa->fa_node;
116 	sc->sc_mii.md_cookie = sc;
117 	sc->sc_mii.md_readreg = mvmdio_smi_readreg;
118 	sc->sc_mii.md_writereg = mvmdio_smi_writereg;
119 	mii_register(&sc->sc_mii);
120 
121 	simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
122 }
123 
124 int
125 mvmdio_smi_readreg(struct device *dev, int phy, int reg)
126 {
127 	struct mvmdio_softc *sc = (struct mvmdio_softc *) dev;
128 	uint32_t smi, val;
129 	int i;
130 
131 	mtx_enter(&sc->sc_mtx);
132 
133 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
134 		DELAY(1);
135 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
136 			break;
137 	}
138 	if (i == MVNETA_PHY_TIMEOUT) {
139 		printf("%s: SMI busy timeout\n", sc->sc_sbus.sc_dev.dv_xname);
140 		mtx_leave(&sc->sc_mtx);
141 		return -1;
142 	}
143 
144 	smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg)
145 	    | MVNETA_SMI_OPCODE_READ;
146 	MVNETA_WRITE(sc, 0, smi);
147 
148 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
149 		DELAY(1);
150 		smi = MVNETA_READ(sc, 0);
151 		if (smi & MVNETA_SMI_READVALID)
152 			break;
153 	}
154 
155 	mtx_leave(&sc->sc_mtx);
156 
157 	val = smi & MVNETA_SMI_DATA_MASK;
158 
159 	return val;
160 }
161 
162 void
163 mvmdio_smi_writereg(struct device *dev, int phy, int reg, int val)
164 {
165 	struct mvmdio_softc *sc = (struct mvmdio_softc *) dev;
166 	uint32_t smi;
167 	int i;
168 
169 	mtx_enter(&sc->sc_mtx);
170 
171 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
172 		DELAY(1);
173 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
174 			break;
175 	}
176 	if (i == MVNETA_PHY_TIMEOUT) {
177 		printf("%s: SMI busy timeout\n", sc->sc_sbus.sc_dev.dv_xname);
178 		mtx_leave(&sc->sc_mtx);
179 		return;
180 	}
181 
182 	smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) |
183 	    MVNETA_SMI_OPCODE_WRITE | (val & MVNETA_SMI_DATA_MASK);
184 	MVNETA_WRITE(sc, 0, smi);
185 
186 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
187 		DELAY(1);
188 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
189 			break;
190 	}
191 
192 	mtx_leave(&sc->sc_mtx);
193 
194 	if (i == MVNETA_PHY_TIMEOUT)
195 		printf("%s: phy write timed out\n", sc->sc_sbus.sc_dev.dv_xname);
196 }
197