xref: /openbsd-src/sys/dev/fdt/mvmdio.c (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1 /*	$OpenBSD: mvmdio.c,v 1.2 2020/06/25 12:39:19 patrick 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 #include <dev/ofw/openfirm.h>
40 #include <dev/ofw/ofw_clock.h>
41 #include <dev/ofw/ofw_pinctrl.h>
42 #include <dev/ofw/ofw_misc.h>
43 #include <dev/ofw/fdt.h>
44 
45 #include <dev/fdt/if_mvnetareg.h>
46 
47 #include <net/if.h>
48 
49 #define MVNETA_READ(sc, reg) \
50 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
51 #define MVNETA_WRITE(sc, reg, val) \
52 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
53 
54 struct mvmdio_softc {
55 	struct device sc_dev;
56 
57 	bus_space_tag_t sc_iot;
58 	bus_space_handle_t sc_ioh;
59 
60 	struct mutex sc_mtx;
61 	struct mii_bus sc_mii;
62 };
63 
64 static int mvmdio_match(struct device *, void *, void *);
65 static void mvmdio_attach(struct device *, struct device *, void *);
66 
67 int mvmdio_smi_readreg(struct device *, int, int);
68 void mvmdio_smi_writereg(struct device *, int, int, int);
69 
70 struct cfdriver mvmdio_cd = {
71 	NULL, "mvmdio", DV_DULL
72 };
73 
74 struct cfattach mvmdio_ca = {
75 	sizeof (struct mvmdio_softc), mvmdio_match, mvmdio_attach,
76 };
77 
78 static int
79 mvmdio_match(struct device *parent, void *cfdata, void *aux)
80 {
81 	struct fdt_attach_args *faa = aux;
82 
83 	return OF_is_compatible(faa->fa_node, "marvell,orion-mdio");
84 }
85 
86 static void
87 mvmdio_attach(struct device *parent, struct device *self, void *aux)
88 {
89 	struct mvmdio_softc *sc = (struct mvmdio_softc *) self;
90 	struct fdt_attach_args *faa = aux;
91 
92 	printf("\n");
93 
94 	sc->sc_iot = faa->fa_iot;
95 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
96 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
97 		panic("%s: cannot map registers", sc->sc_dev.dv_xname);
98 
99 	pinctrl_byname(faa->fa_node, "default");
100 	clock_enable_all(faa->fa_node);
101 
102 	mtx_init(&sc->sc_mtx, IPL_NET);
103 
104 	sc->sc_mii.md_node = faa->fa_node;
105 	sc->sc_mii.md_cookie = sc;
106 	sc->sc_mii.md_readreg = mvmdio_smi_readreg;
107 	sc->sc_mii.md_writereg = mvmdio_smi_writereg;
108 	mii_register(&sc->sc_mii);
109 }
110 
111 int
112 mvmdio_smi_readreg(struct device *dev, int phy, int reg)
113 {
114 	struct mvmdio_softc *sc = (struct mvmdio_softc *) dev;
115 	uint32_t smi, val;
116 	int i;
117 
118 	mtx_enter(&sc->sc_mtx);
119 
120 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
121 		DELAY(1);
122 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
123 			break;
124 	}
125 	if (i == MVNETA_PHY_TIMEOUT) {
126 		printf("%s: SMI busy timeout\n", sc->sc_dev.dv_xname);
127 		mtx_leave(&sc->sc_mtx);
128 		return -1;
129 	}
130 
131 	smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg)
132 	    | MVNETA_SMI_OPCODE_READ;
133 	MVNETA_WRITE(sc, 0, smi);
134 
135 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
136 		DELAY(1);
137 		smi = MVNETA_READ(sc, 0);
138 		if (smi & MVNETA_SMI_READVALID)
139 			break;
140 	}
141 
142 	mtx_leave(&sc->sc_mtx);
143 
144 	val = smi & MVNETA_SMI_DATA_MASK;
145 
146 	return val;
147 }
148 
149 void
150 mvmdio_smi_writereg(struct device *dev, int phy, int reg, int val)
151 {
152 	struct mvmdio_softc *sc = (struct mvmdio_softc *) dev;
153 	uint32_t smi;
154 	int i;
155 
156 	mtx_enter(&sc->sc_mtx);
157 
158 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
159 		DELAY(1);
160 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
161 			break;
162 	}
163 	if (i == MVNETA_PHY_TIMEOUT) {
164 		printf("%s: SMI busy timeout\n", sc->sc_dev.dv_xname);
165 		mtx_leave(&sc->sc_mtx);
166 		return;
167 	}
168 
169 	smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) |
170 	    MVNETA_SMI_OPCODE_WRITE | (val & MVNETA_SMI_DATA_MASK);
171 	MVNETA_WRITE(sc, 0, smi);
172 
173 	for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) {
174 		DELAY(1);
175 		if (!(MVNETA_READ(sc, 0) & MVNETA_SMI_BUSY))
176 			break;
177 	}
178 
179 	mtx_leave(&sc->sc_mtx);
180 
181 	if (i == MVNETA_PHY_TIMEOUT)
182 		printf("%s: phy write timed out\n", sc->sc_dev.dv_xname);
183 }
184