xref: /freebsd/sys/dev/etherswitch/arswitch/arswitch_reg.c (revision 26aff2abad8bc3fcf96b49ef590974a8306cba7e)
1a043e8c7SAdrian Chadd /*-
2a043e8c7SAdrian Chadd  * Copyright (c) 2011-2012 Stefan Bethke.
3a043e8c7SAdrian Chadd  * All rights reserved.
4a043e8c7SAdrian Chadd  *
5a043e8c7SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6a043e8c7SAdrian Chadd  * modification, are permitted provided that the following conditions
7a043e8c7SAdrian Chadd  * are met:
8a043e8c7SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9a043e8c7SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
10a043e8c7SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
11a043e8c7SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
12a043e8c7SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
13a043e8c7SAdrian Chadd  *
14a043e8c7SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a043e8c7SAdrian Chadd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a043e8c7SAdrian Chadd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a043e8c7SAdrian Chadd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a043e8c7SAdrian Chadd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a043e8c7SAdrian Chadd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a043e8c7SAdrian Chadd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a043e8c7SAdrian Chadd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a043e8c7SAdrian Chadd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a043e8c7SAdrian Chadd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a043e8c7SAdrian Chadd  * SUCH DAMAGE.
25a043e8c7SAdrian Chadd  *
26a043e8c7SAdrian Chadd  * $FreeBSD$
27a043e8c7SAdrian Chadd  */
28a043e8c7SAdrian Chadd 
29a043e8c7SAdrian Chadd #include <sys/param.h>
30a043e8c7SAdrian Chadd #include <sys/bus.h>
31a043e8c7SAdrian Chadd #include <sys/errno.h>
32a043e8c7SAdrian Chadd #include <sys/kernel.h>
33a043e8c7SAdrian Chadd #include <sys/module.h>
34a043e8c7SAdrian Chadd #include <sys/socket.h>
35a043e8c7SAdrian Chadd #include <sys/sockio.h>
36a043e8c7SAdrian Chadd #include <sys/sysctl.h>
37a043e8c7SAdrian Chadd #include <sys/systm.h>
38a043e8c7SAdrian Chadd 
39a043e8c7SAdrian Chadd #include <net/if.h>
40a043e8c7SAdrian Chadd #include <net/if_arp.h>
41a043e8c7SAdrian Chadd #include <net/ethernet.h>
42a043e8c7SAdrian Chadd #include <net/if_dl.h>
43a043e8c7SAdrian Chadd #include <net/if_media.h>
44a043e8c7SAdrian Chadd #include <net/if_types.h>
45a043e8c7SAdrian Chadd 
46a043e8c7SAdrian Chadd #include <machine/bus.h>
47a043e8c7SAdrian Chadd #include <dev/iicbus/iic.h>
48a043e8c7SAdrian Chadd #include <dev/iicbus/iiconf.h>
49a043e8c7SAdrian Chadd #include <dev/iicbus/iicbus.h>
50a043e8c7SAdrian Chadd #include <dev/mii/mii.h>
51a043e8c7SAdrian Chadd #include <dev/mii/miivar.h>
52a043e8c7SAdrian Chadd #include <dev/etherswitch/mdio.h>
53a043e8c7SAdrian Chadd 
54a043e8c7SAdrian Chadd #include <dev/etherswitch/etherswitch.h>
55a043e8c7SAdrian Chadd 
56a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h>
57a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h>
58a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h>
59a043e8c7SAdrian Chadd 
60a043e8c7SAdrian Chadd #include "mdio_if.h"
61a043e8c7SAdrian Chadd #include "miibus_if.h"
62a043e8c7SAdrian Chadd #include "etherswitch_if.h"
63a043e8c7SAdrian Chadd 
64a043e8c7SAdrian Chadd static inline void
65a043e8c7SAdrian Chadd arswitch_split_setpage(device_t dev, uint32_t addr, uint16_t *phy,
66a043e8c7SAdrian Chadd     uint16_t *reg)
67a043e8c7SAdrian Chadd {
68a043e8c7SAdrian Chadd 	struct arswitch_softc *sc = device_get_softc(dev);
69a043e8c7SAdrian Chadd 	uint16_t page;
70a043e8c7SAdrian Chadd 
71a043e8c7SAdrian Chadd 	page = ((addr) >> 9) & 0xffff;
72a043e8c7SAdrian Chadd 	*phy = (((addr) >> 6) & 0x07) | 0x10;
73a043e8c7SAdrian Chadd 	*reg = ((addr) >> 1) & 0x1f;
74a043e8c7SAdrian Chadd 
75a043e8c7SAdrian Chadd 	if (sc->page != page) {
76a043e8c7SAdrian Chadd 		MDIO_WRITEREG(device_get_parent(dev), 0x18, 0, page);
77a043e8c7SAdrian Chadd 		sc->page = page;
78a043e8c7SAdrian Chadd 	}
79a043e8c7SAdrian Chadd }
80a043e8c7SAdrian Chadd 
81a043e8c7SAdrian Chadd /*
82a043e8c7SAdrian Chadd  * Read half a register.  Some of the registers define control bits, and
83a043e8c7SAdrian Chadd  * the sequence of half-word accesses matters.  The register addresses
84a043e8c7SAdrian Chadd  * are word-even (mod 4).
85a043e8c7SAdrian Chadd  */
86a043e8c7SAdrian Chadd static inline int
87a043e8c7SAdrian Chadd arswitch_readreg16(device_t dev, int addr)
88a043e8c7SAdrian Chadd {
89a043e8c7SAdrian Chadd 	uint16_t phy, reg;
90a043e8c7SAdrian Chadd 
91a043e8c7SAdrian Chadd 	arswitch_split_setpage(dev, addr, &phy, &reg);
92a043e8c7SAdrian Chadd 	return (MDIO_READREG(device_get_parent(dev), phy, reg));
93a043e8c7SAdrian Chadd }
94a043e8c7SAdrian Chadd 
95a043e8c7SAdrian Chadd /*
96a043e8c7SAdrian Chadd  * XXX NOTE:
97a043e8c7SAdrian Chadd  *
98a043e8c7SAdrian Chadd  * This may not work for AR7240 series embedded switches -
99a043e8c7SAdrian Chadd  * the per-PHY register space doesn't seem to be exposed.
100a043e8c7SAdrian Chadd  *
101a043e8c7SAdrian Chadd  * In that instance, it may be required to speak via
102a043e8c7SAdrian Chadd  * the internal switch PHY MDIO bus indirection.
103a043e8c7SAdrian Chadd  */
104a043e8c7SAdrian Chadd void
105a043e8c7SAdrian Chadd arswitch_writedbg(device_t dev, int phy, uint16_t dbg_addr,
106a043e8c7SAdrian Chadd     uint16_t dbg_data)
107a043e8c7SAdrian Chadd {
108a043e8c7SAdrian Chadd 	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
109a043e8c7SAdrian Chadd 	    MII_ATH_DBG_ADDR, dbg_addr);
110a043e8c7SAdrian Chadd 	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
111a043e8c7SAdrian Chadd 	    MII_ATH_DBG_DATA, dbg_data);
112a043e8c7SAdrian Chadd }
113a043e8c7SAdrian Chadd 
114a043e8c7SAdrian Chadd /*
115a043e8c7SAdrian Chadd  * Write half a register
116a043e8c7SAdrian Chadd  */
117a043e8c7SAdrian Chadd static inline int
118a043e8c7SAdrian Chadd arswitch_writereg16(device_t dev, int addr, int data)
119a043e8c7SAdrian Chadd {
120a043e8c7SAdrian Chadd 	uint16_t phy, reg;
121a043e8c7SAdrian Chadd 
122a043e8c7SAdrian Chadd 	arswitch_split_setpage(dev, addr, &phy, &reg);
123a043e8c7SAdrian Chadd 	return (MDIO_WRITEREG(device_get_parent(dev), phy, reg, data));
124a043e8c7SAdrian Chadd }
125a043e8c7SAdrian Chadd 
126a043e8c7SAdrian Chadd int
127a043e8c7SAdrian Chadd arswitch_readreg_lsb(device_t dev, int addr)
128a043e8c7SAdrian Chadd {
129a043e8c7SAdrian Chadd 
130a043e8c7SAdrian Chadd 	return (arswitch_readreg16(dev, addr));
131a043e8c7SAdrian Chadd }
132a043e8c7SAdrian Chadd 
133a043e8c7SAdrian Chadd int
134a043e8c7SAdrian Chadd arswitch_readreg_msb(device_t dev, int addr)
135a043e8c7SAdrian Chadd {
136a043e8c7SAdrian Chadd 
137a043e8c7SAdrian Chadd 	return (arswitch_readreg16(dev, addr + 2) << 16);
138a043e8c7SAdrian Chadd }
139a043e8c7SAdrian Chadd 
140a043e8c7SAdrian Chadd int
141a043e8c7SAdrian Chadd arswitch_writereg_lsb(device_t dev, int addr, int data)
142a043e8c7SAdrian Chadd {
143a043e8c7SAdrian Chadd 
144a043e8c7SAdrian Chadd 	return (arswitch_writereg16(dev, addr, data & 0xffff));
145a043e8c7SAdrian Chadd }
146a043e8c7SAdrian Chadd 
147a043e8c7SAdrian Chadd int
148a043e8c7SAdrian Chadd arswitch_writereg_msb(device_t dev, int addr, int data)
149a043e8c7SAdrian Chadd {
150a043e8c7SAdrian Chadd 
151*26aff2abSAleksandr Rybalko 	return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff));
152a043e8c7SAdrian Chadd }
153a043e8c7SAdrian Chadd 
154a043e8c7SAdrian Chadd int
155a043e8c7SAdrian Chadd arswitch_readreg(device_t dev, int addr)
156a043e8c7SAdrian Chadd {
157a043e8c7SAdrian Chadd 
158a043e8c7SAdrian Chadd 	return (arswitch_readreg_lsb(dev, addr) |
159a043e8c7SAdrian Chadd 	    arswitch_readreg_msb(dev, addr));
160a043e8c7SAdrian Chadd }
161a043e8c7SAdrian Chadd 
162a043e8c7SAdrian Chadd int
163a043e8c7SAdrian Chadd arswitch_writereg(device_t dev, int addr, int value)
164a043e8c7SAdrian Chadd {
165a043e8c7SAdrian Chadd 
166a043e8c7SAdrian Chadd 	/* XXX Check the first write too? */
167a043e8c7SAdrian Chadd 	arswitch_writereg_lsb(dev, addr, value);
168a043e8c7SAdrian Chadd 	return (arswitch_writereg_msb(dev, addr, value));
169a043e8c7SAdrian Chadd }
170a043e8c7SAdrian Chadd 
171a043e8c7SAdrian Chadd int
172a043e8c7SAdrian Chadd arswitch_modifyreg(device_t dev, int addr, int mask, int set)
173a043e8c7SAdrian Chadd {
174a043e8c7SAdrian Chadd 	int value;
175a043e8c7SAdrian Chadd 
176a043e8c7SAdrian Chadd 	value = arswitch_readreg(dev, addr);
177a043e8c7SAdrian Chadd 	value &= ~mask;
178a043e8c7SAdrian Chadd 	value |= set;
179a043e8c7SAdrian Chadd 	return (arswitch_writereg(dev, addr, value));
180a043e8c7SAdrian Chadd }
181