1235288Sadrian/*-
2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke.
3235288Sadrian * All rights reserved.
4235288Sadrian *
5235288Sadrian * Redistribution and use in source and binary forms, with or without
6235288Sadrian * modification, are permitted provided that the following conditions
7235288Sadrian * are met:
8235288Sadrian * 1. Redistributions of source code must retain the above copyright
9235288Sadrian *    notice, this list of conditions and the following disclaimer.
10235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright
11235288Sadrian *    notice, this list of conditions and the following disclaimer in the
12235288Sadrian *    documentation and/or other materials provided with the distribution.
13235288Sadrian *
14235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235288Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235288Sadrian * SUCH DAMAGE.
25235288Sadrian *
26235288Sadrian * $FreeBSD: releng/11.0/sys/dev/etherswitch/arswitch/arswitch_reg.c 292738 2015-12-26 02:31:39Z adrian $
27235288Sadrian */
28235288Sadrian
29235288Sadrian#include <sys/param.h>
30235288Sadrian#include <sys/bus.h>
31235288Sadrian#include <sys/errno.h>
32235288Sadrian#include <sys/kernel.h>
33235288Sadrian#include <sys/module.h>
34235288Sadrian#include <sys/socket.h>
35235288Sadrian#include <sys/sockio.h>
36235288Sadrian#include <sys/sysctl.h>
37235288Sadrian#include <sys/systm.h>
38235288Sadrian
39235288Sadrian#include <net/if.h>
40235288Sadrian#include <net/if_arp.h>
41235288Sadrian#include <net/ethernet.h>
42235288Sadrian#include <net/if_dl.h>
43235288Sadrian#include <net/if_media.h>
44235288Sadrian#include <net/if_types.h>
45235288Sadrian
46235288Sadrian#include <machine/bus.h>
47268564Srpaulo#include <dev/iicbus/iic.h>
48235288Sadrian#include <dev/iicbus/iiconf.h>
49235288Sadrian#include <dev/iicbus/iicbus.h>
50235288Sadrian#include <dev/mii/mii.h>
51235288Sadrian#include <dev/mii/miivar.h>
52292738Sadrian#include <dev/mdio/mdio.h>
53235288Sadrian
54235288Sadrian#include <dev/etherswitch/etherswitch.h>
55235288Sadrian
56235288Sadrian#include <dev/etherswitch/arswitch/arswitchreg.h>
57235288Sadrian#include <dev/etherswitch/arswitch/arswitchvar.h>
58235288Sadrian#include <dev/etherswitch/arswitch/arswitch_reg.h>
59235288Sadrian
60235288Sadrian#include "mdio_if.h"
61235288Sadrian#include "miibus_if.h"
62235288Sadrian#include "etherswitch_if.h"
63235288Sadrian
64235288Sadrianstatic inline void
65235288Sadrianarswitch_split_setpage(device_t dev, uint32_t addr, uint16_t *phy,
66235288Sadrian    uint16_t *reg)
67235288Sadrian{
68235288Sadrian	struct arswitch_softc *sc = device_get_softc(dev);
69235288Sadrian	uint16_t page;
70235288Sadrian
71279767Sadrian	page = (addr >> 9) & 0x1ff;
72279767Sadrian	*phy = (addr >> 6) & 0x7;
73279767Sadrian	*reg = (addr >> 1) & 0x1f;
74235288Sadrian
75253570Sloos	if (sc->page != page) {
76253570Sloos		MDIO_WRITEREG(device_get_parent(dev), 0x18, 0, page);
77279767Sadrian		DELAY(2000);
78253570Sloos		sc->page = page;
79253570Sloos	}
80235288Sadrian}
81235288Sadrian
82235288Sadrian/*
83235288Sadrian * Read half a register.  Some of the registers define control bits, and
84235288Sadrian * the sequence of half-word accesses matters.  The register addresses
85235288Sadrian * are word-even (mod 4).
86235288Sadrian */
87235288Sadrianstatic inline int
88235288Sadrianarswitch_readreg16(device_t dev, int addr)
89235288Sadrian{
90235288Sadrian	uint16_t phy, reg;
91279767Sadrian
92235288Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
93279767Sadrian	return (MDIO_READREG(device_get_parent(dev), 0x10 | phy, reg));
94235288Sadrian}
95235288Sadrian
96235288Sadrian/*
97279767Sadrian * Write half a register.  See above!
98279767Sadrian */
99279767Sadrianstatic inline int
100279767Sadrianarswitch_writereg16(device_t dev, int addr, int data)
101279767Sadrian{
102279767Sadrian	uint16_t phy, reg;
103279767Sadrian
104279767Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
105279767Sadrian	return (MDIO_WRITEREG(device_get_parent(dev), 0x10 | phy, reg, data));
106279767Sadrian}
107279767Sadrian
108279767Sadrian/*
109235288Sadrian * XXX NOTE:
110235288Sadrian *
111235288Sadrian * This may not work for AR7240 series embedded switches -
112235288Sadrian * the per-PHY register space doesn't seem to be exposed.
113235288Sadrian *
114235288Sadrian * In that instance, it may be required to speak via
115235288Sadrian * the internal switch PHY MDIO bus indirection.
116235288Sadrian */
117235288Sadrianvoid
118235288Sadrianarswitch_writedbg(device_t dev, int phy, uint16_t dbg_addr,
119235288Sadrian    uint16_t dbg_data)
120235288Sadrian{
121235288Sadrian	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
122235288Sadrian	    MII_ATH_DBG_ADDR, dbg_addr);
123235288Sadrian	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
124235288Sadrian	    MII_ATH_DBG_DATA, dbg_data);
125235288Sadrian}
126235288Sadrian
127262010Sadrianvoid
128262010Sadrianarswitch_writemmd(device_t dev, int phy, uint16_t dbg_addr,
129262010Sadrian    uint16_t dbg_data)
130262010Sadrian{
131262010Sadrian	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
132262010Sadrian	    MII_ATH_MMD_ADDR, dbg_addr);
133262010Sadrian	(void) MDIO_WRITEREG(device_get_parent(dev), phy,
134262010Sadrian	    MII_ATH_MMD_DATA, dbg_data);
135262010Sadrian}
136262010Sadrian
137279767Sadrianstatic uint32_t
138279767Sadrianarswitch_reg_read32(device_t dev, int phy, int reg)
139235288Sadrian{
140279767Sadrian	uint16_t lo, hi;
141279767Sadrian	lo = MDIO_READREG(device_get_parent(dev), phy, reg);
142279767Sadrian	hi = MDIO_READREG(device_get_parent(dev), phy, reg + 1);
143279767Sadrian
144279767Sadrian	return (hi << 16) | lo;
145235288Sadrian}
146235288Sadrian
147279767Sadrianstatic int
148279767Sadrianarswitch_reg_write32(device_t dev, int phy, int reg, uint32_t value)
149235288Sadrian{
150279767Sadrian	struct arswitch_softc *sc;
151279767Sadrian	int r;
152279767Sadrian	uint16_t lo, hi;
153235288Sadrian
154279767Sadrian	sc = device_get_softc(dev);
155279767Sadrian	lo = value & 0xffff;
156279767Sadrian	hi = (uint16_t) (value >> 16);
157279767Sadrian
158279767Sadrian	if (sc->mii_lo_first) {
159279767Sadrian		r = MDIO_WRITEREG(device_get_parent(dev),
160279767Sadrian		    phy, reg, lo);
161279767Sadrian		r |= MDIO_WRITEREG(device_get_parent(dev),
162279767Sadrian		    phy, reg + 1, hi);
163279767Sadrian	} else {
164279767Sadrian		r = MDIO_WRITEREG(device_get_parent(dev),
165279767Sadrian		    phy, reg + 1, hi);
166279767Sadrian		r |= MDIO_WRITEREG(device_get_parent(dev),
167279767Sadrian		    phy, reg, lo);
168279767Sadrian	}
169279767Sadrian
170279767Sadrian	return r;
171235288Sadrian}
172235288Sadrian
173235288Sadrianint
174279767Sadrianarswitch_readreg(device_t dev, int addr)
175235288Sadrian{
176279767Sadrian	uint16_t phy, reg;
177235288Sadrian
178279767Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
179279767Sadrian	return arswitch_reg_read32(dev, 0x10 | phy, reg);
180235288Sadrian}
181235288Sadrian
182235288Sadrianint
183279767Sadrianarswitch_writereg(device_t dev, int addr, int value)
184235288Sadrian{
185279767Sadrian	struct arswitch_softc *sc;
186279767Sadrian	uint16_t phy, reg;
187235288Sadrian
188279767Sadrian	sc = device_get_softc(dev);
189279767Sadrian
190279767Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
191279767Sadrian	return (arswitch_reg_write32(dev, 0x10 | phy, reg, value));
192235288Sadrian}
193235288Sadrian
194279767Sadrian/*
195279767Sadrian * Read/write 16 bit values in the switch register space.
196279767Sadrian *
197279767Sadrian * Some of the registers are control registers (eg the MDIO
198279767Sadrian * data versus control space) and so need to be treated
199279767Sadrian * differently.
200279767Sadrian */
201235288Sadrianint
202279767Sadrianarswitch_readreg_lsb(device_t dev, int addr)
203235288Sadrian{
204235288Sadrian
205279767Sadrian	return (arswitch_readreg16(dev, addr));
206235288Sadrian}
207235288Sadrian
208235288Sadrianint
209279767Sadrianarswitch_readreg_msb(device_t dev, int addr)
210235288Sadrian{
211235288Sadrian
212279767Sadrian	return (arswitch_readreg16(dev, addr + 2) << 16);
213235288Sadrian}
214235288Sadrian
215235288Sadrianint
216279767Sadrianarswitch_writereg_lsb(device_t dev, int addr, int data)
217235288Sadrian{
218235288Sadrian
219279767Sadrian	return (arswitch_writereg16(dev, addr, data & 0xffff));
220279767Sadrian}
221262200Sadrian
222279767Sadrianint
223279767Sadrianarswitch_writereg_msb(device_t dev, int addr, int data)
224279767Sadrian{
225262200Sadrian
226279767Sadrian	return (arswitch_writereg16(dev, addr + 2, (data >> 16) & 0xffff));
227235288Sadrian}
228235288Sadrian
229235288Sadrianint
230235288Sadrianarswitch_modifyreg(device_t dev, int addr, int mask, int set)
231235288Sadrian{
232235288Sadrian	int value;
233279767Sadrian	uint16_t phy, reg;
234279767Sadrian
235279767Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
236279767Sadrian
237279767Sadrian	value = arswitch_reg_read32(dev, 0x10 | phy, reg);
238235288Sadrian	value &= ~mask;
239235288Sadrian	value |= set;
240279767Sadrian	return (arswitch_reg_write32(dev, 0x10 | phy, reg, value));
241235288Sadrian}
242253572Sloos
243253572Sloosint
244253572Sloosarswitch_waitreg(device_t dev, int addr, int mask, int val, int timeout)
245253572Sloos{
246253572Sloos	int err, v;
247279767Sadrian	uint16_t phy, reg;
248253572Sloos
249279767Sadrian	arswitch_split_setpage(dev, addr, &phy, &reg);
250279767Sadrian
251253572Sloos	err = -1;
252253572Sloos	while (1) {
253279767Sadrian		v = arswitch_reg_read32(dev, 0x10 | phy, reg);
254253572Sloos		v &= mask;
255253572Sloos		if (v == val) {
256253572Sloos			err = 0;
257253572Sloos			break;
258253572Sloos		}
259253572Sloos		if (!timeout)
260253572Sloos			break;
261253572Sloos		DELAY(1);
262253572Sloos		timeout--;
263253572Sloos	}
264253572Sloos	return (err);
265253572Sloos}
266