xref: /freebsd/sys/dev/etherswitch/arswitch/arswitch_phy.c (revision e765499eed85adebd9e06c2535bbb10400929248)
1a043e8c7SAdrian Chadd /*-
2a043e8c7SAdrian Chadd  * Copyright (c) 2011-2012 Stefan Bethke.
3a043e8c7SAdrian Chadd  * Copyright (c) 2012 Adrian Chadd.
4a043e8c7SAdrian Chadd  * All rights reserved.
5a043e8c7SAdrian Chadd  *
6a043e8c7SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
7a043e8c7SAdrian Chadd  * modification, are permitted provided that the following conditions
8a043e8c7SAdrian Chadd  * are met:
9a043e8c7SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
10a043e8c7SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
11a043e8c7SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
12a043e8c7SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
13a043e8c7SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
14a043e8c7SAdrian Chadd  *
15a043e8c7SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16a043e8c7SAdrian Chadd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17a043e8c7SAdrian Chadd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a043e8c7SAdrian Chadd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19a043e8c7SAdrian Chadd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a043e8c7SAdrian Chadd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a043e8c7SAdrian Chadd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a043e8c7SAdrian Chadd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a043e8c7SAdrian Chadd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a043e8c7SAdrian Chadd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a043e8c7SAdrian Chadd  * SUCH DAMAGE.
26a043e8c7SAdrian Chadd  *
27a043e8c7SAdrian Chadd  * $FreeBSD$
28a043e8c7SAdrian Chadd  */
29a043e8c7SAdrian Chadd 
30a043e8c7SAdrian Chadd #include <sys/param.h>
31a043e8c7SAdrian Chadd #include <sys/bus.h>
32a043e8c7SAdrian Chadd #include <sys/errno.h>
33a043e8c7SAdrian Chadd #include <sys/kernel.h>
34104dc214SGleb Smirnoff #include <sys/lock.h>
35a043e8c7SAdrian Chadd #include <sys/module.h>
36104dc214SGleb Smirnoff #include <sys/mutex.h>
37a043e8c7SAdrian Chadd #include <sys/socket.h>
38a043e8c7SAdrian Chadd #include <sys/sockio.h>
39a043e8c7SAdrian Chadd #include <sys/sysctl.h>
40a043e8c7SAdrian Chadd #include <sys/systm.h>
41a043e8c7SAdrian Chadd 
42a043e8c7SAdrian Chadd #include <net/if.h>
43a043e8c7SAdrian Chadd #include <net/if_media.h>
44a043e8c7SAdrian Chadd 
45a043e8c7SAdrian Chadd #include <machine/bus.h>
46a043e8c7SAdrian Chadd #include <dev/iicbus/iic.h>
47a043e8c7SAdrian Chadd #include <dev/iicbus/iiconf.h>
48a043e8c7SAdrian Chadd #include <dev/iicbus/iicbus.h>
49a043e8c7SAdrian Chadd #include <dev/mii/mii.h>
50a043e8c7SAdrian Chadd #include <dev/mii/miivar.h>
51a043e8c7SAdrian Chadd #include <dev/etherswitch/mdio.h>
52a043e8c7SAdrian Chadd 
53a043e8c7SAdrian Chadd #include <dev/etherswitch/etherswitch.h>
54a043e8c7SAdrian Chadd 
55a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h>
56a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h>
57a043e8c7SAdrian Chadd 
58a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h>
59a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_phy.h>
60a043e8c7SAdrian Chadd 
61a043e8c7SAdrian Chadd #include "mdio_if.h"
62a043e8c7SAdrian Chadd #include "miibus_if.h"
63a043e8c7SAdrian Chadd #include "etherswitch_if.h"
64a043e8c7SAdrian Chadd 
65a043e8c7SAdrian Chadd #if	defined(DEBUG)
66a043e8c7SAdrian Chadd static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch");
67a043e8c7SAdrian Chadd #endif
68a043e8c7SAdrian Chadd 
69a043e8c7SAdrian Chadd /*
70a043e8c7SAdrian Chadd  * access PHYs integrated into the switch chip through the switch's MDIO
71a043e8c7SAdrian Chadd  * control register.
72a043e8c7SAdrian Chadd  */
73a043e8c7SAdrian Chadd int
74a043e8c7SAdrian Chadd arswitch_readphy(device_t dev, int phy, int reg)
75a043e8c7SAdrian Chadd {
76454d507aSAleksandr Rybalko 	struct arswitch_softc *sc;
77a043e8c7SAdrian Chadd 	uint32_t data = 0, ctrl;
78a043e8c7SAdrian Chadd 	int err, timeout;
79*e765499eSAdrian Chadd 	uint32_t a;
80a043e8c7SAdrian Chadd 
81454d507aSAleksandr Rybalko 	sc = device_get_softc(dev);
82454d507aSAleksandr Rybalko 	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
83454d507aSAleksandr Rybalko 
84a043e8c7SAdrian Chadd 	if (phy < 0 || phy >= 32)
85a043e8c7SAdrian Chadd 		return (ENXIO);
86a043e8c7SAdrian Chadd 	if (reg < 0 || reg >= 32)
87a043e8c7SAdrian Chadd 		return (ENXIO);
88454d507aSAleksandr Rybalko 
89*e765499eSAdrian Chadd 	if (AR8X16_IS_SWITCH(sc, AR8327))
90*e765499eSAdrian Chadd 		a = AR8327_REG_MDIO_CTRL;
91*e765499eSAdrian Chadd 	else
92*e765499eSAdrian Chadd 		a = AR8X16_REG_MDIO_CTRL;
93*e765499eSAdrian Chadd 
94454d507aSAleksandr Rybalko 	ARSWITCH_LOCK(sc);
95*e765499eSAdrian Chadd 	err = arswitch_writereg_msb(dev, a,
96a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN |
97a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_CMD_READ |
98a043e8c7SAdrian Chadd 	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
99a043e8c7SAdrian Chadd 	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT));
100a043e8c7SAdrian Chadd 	DEVERR(dev, err, "arswitch_readphy()=%d: phy=%d.%02x\n", phy, reg);
101a043e8c7SAdrian Chadd 	if (err != 0)
102454d507aSAleksandr Rybalko 		goto fail;
103a043e8c7SAdrian Chadd 	for (timeout = 100; timeout--; ) {
104*e765499eSAdrian Chadd 		ctrl = arswitch_readreg_msb(dev, a);
105a043e8c7SAdrian Chadd 		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
106a043e8c7SAdrian Chadd 			break;
107a043e8c7SAdrian Chadd 	}
108a043e8c7SAdrian Chadd 	if (timeout < 0)
109454d507aSAleksandr Rybalko 		goto fail;
110*e765499eSAdrian Chadd 	data = arswitch_readreg_lsb(dev, a) &
111a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_DATA_MASK;
112454d507aSAleksandr Rybalko 	ARSWITCH_UNLOCK(sc);
113a043e8c7SAdrian Chadd 	return (data);
114454d507aSAleksandr Rybalko 
115454d507aSAleksandr Rybalko fail:
116454d507aSAleksandr Rybalko 	ARSWITCH_UNLOCK(sc);
117454d507aSAleksandr Rybalko 	return (-1);
118a043e8c7SAdrian Chadd }
119a043e8c7SAdrian Chadd 
120a043e8c7SAdrian Chadd int
121a043e8c7SAdrian Chadd arswitch_writephy(device_t dev, int phy, int reg, int data)
122a043e8c7SAdrian Chadd {
123454d507aSAleksandr Rybalko 	struct arswitch_softc *sc;
124a043e8c7SAdrian Chadd 	uint32_t ctrl;
125a043e8c7SAdrian Chadd 	int err, timeout;
126*e765499eSAdrian Chadd 	uint32_t a;
127a043e8c7SAdrian Chadd 
128454d507aSAleksandr Rybalko 	sc = device_get_softc(dev);
129454d507aSAleksandr Rybalko 	ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED);
130454d507aSAleksandr Rybalko 
131a043e8c7SAdrian Chadd 	if (reg < 0 || reg >= 32)
132a043e8c7SAdrian Chadd 		return (ENXIO);
133454d507aSAleksandr Rybalko 
134*e765499eSAdrian Chadd 	if (AR8X16_IS_SWITCH(sc, AR8327))
135*e765499eSAdrian Chadd 		a = AR8327_REG_MDIO_CTRL;
136*e765499eSAdrian Chadd 	else
137*e765499eSAdrian Chadd 		a = AR8X16_REG_MDIO_CTRL;
138*e765499eSAdrian Chadd 
139454d507aSAleksandr Rybalko 	ARSWITCH_LOCK(sc);
140*e765499eSAdrian Chadd 	err = arswitch_writereg(dev, a,
141a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_BUSY |
142a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_MASTER_EN |
143a043e8c7SAdrian Chadd 	    AR8X16_MDIO_CTRL_CMD_WRITE |
144a043e8c7SAdrian Chadd 	    (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) |
1459604b6acSLuiz Otavio O Souza 	    (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT) |
1469604b6acSLuiz Otavio O Souza 	    (data & AR8X16_MDIO_CTRL_DATA_MASK));
147a043e8c7SAdrian Chadd 	if (err != 0)
148454d507aSAleksandr Rybalko 		goto out;
149a043e8c7SAdrian Chadd 	for (timeout = 100; timeout--; ) {
150*e765499eSAdrian Chadd 		ctrl = arswitch_readreg(dev, a);
151a043e8c7SAdrian Chadd 		if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0)
152a043e8c7SAdrian Chadd 			break;
153a043e8c7SAdrian Chadd 	}
154a043e8c7SAdrian Chadd 	if (timeout < 0)
155a043e8c7SAdrian Chadd 		err = EIO;
156454d507aSAleksandr Rybalko out:
157a043e8c7SAdrian Chadd 	DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg);
158454d507aSAleksandr Rybalko 	ARSWITCH_UNLOCK(sc);
159a043e8c7SAdrian Chadd 	return (err);
160a043e8c7SAdrian Chadd }
161