xref: /onnv-gate/usr/src/uts/common/io/atge/atge_mii.c (revision 11353:db56a54bf91c)
110393SSaurabh.Mishra@Sun.COM /*
210393SSaurabh.Mishra@Sun.COM  * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
310393SSaurabh.Mishra@Sun.COM  * All rights reserved.
410393SSaurabh.Mishra@Sun.COM  *
510393SSaurabh.Mishra@Sun.COM  * Redistribution and use in source and binary forms, with or without
610393SSaurabh.Mishra@Sun.COM  * modification, are permitted provided that the following conditions
710393SSaurabh.Mishra@Sun.COM  * are met:
810393SSaurabh.Mishra@Sun.COM  * 1. Redistributions of source code must retain the above copyright
910393SSaurabh.Mishra@Sun.COM  *    notice unmodified, this list of conditions, and the following
1010393SSaurabh.Mishra@Sun.COM  *    disclaimer.
1110393SSaurabh.Mishra@Sun.COM  * 2. Redistributions in binary form must reproduce the above copyright
1210393SSaurabh.Mishra@Sun.COM  *    notice, this list of conditions and the following disclaimer in the
1310393SSaurabh.Mishra@Sun.COM  *    documentation and/or other materials provided with the distribution.
1410393SSaurabh.Mishra@Sun.COM  *
1510393SSaurabh.Mishra@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1610393SSaurabh.Mishra@Sun.COM  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1710393SSaurabh.Mishra@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1810393SSaurabh.Mishra@Sun.COM  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1910393SSaurabh.Mishra@Sun.COM  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2010393SSaurabh.Mishra@Sun.COM  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2110393SSaurabh.Mishra@Sun.COM  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2210393SSaurabh.Mishra@Sun.COM  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2310393SSaurabh.Mishra@Sun.COM  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2410393SSaurabh.Mishra@Sun.COM  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2510393SSaurabh.Mishra@Sun.COM  * SUCH DAMAGE.
2610393SSaurabh.Mishra@Sun.COM  */
2710393SSaurabh.Mishra@Sun.COM 
2810393SSaurabh.Mishra@Sun.COM #include <sys/mii.h>
2910393SSaurabh.Mishra@Sun.COM #include <sys/miiregs.h>
3010393SSaurabh.Mishra@Sun.COM 
3110393SSaurabh.Mishra@Sun.COM #include "atge.h"
3210393SSaurabh.Mishra@Sun.COM #include "atge_cmn_reg.h"
3310393SSaurabh.Mishra@Sun.COM #include "atge_l1e_reg.h"
34*11353SSaurabh.Mishra@Sun.COM #include "atge_l1_reg.h"
3510393SSaurabh.Mishra@Sun.COM 
3610393SSaurabh.Mishra@Sun.COM uint16_t
atge_mii_read(void * arg,uint8_t phy,uint8_t reg)3710393SSaurabh.Mishra@Sun.COM atge_mii_read(void *arg, uint8_t phy, uint8_t reg)
3810393SSaurabh.Mishra@Sun.COM {
3910393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep = arg;
4010393SSaurabh.Mishra@Sun.COM 	uint32_t v;
4110393SSaurabh.Mishra@Sun.COM 	int i;
4210393SSaurabh.Mishra@Sun.COM 
4310393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_mii_lock);
4410393SSaurabh.Mishra@Sun.COM 
4510393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
4610393SSaurabh.Mishra@Sun.COM 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
4710393SSaurabh.Mishra@Sun.COM 
4810393SSaurabh.Mishra@Sun.COM 	for (i = PHY_TIMEOUT; i > 0; i--) {
4910393SSaurabh.Mishra@Sun.COM 		drv_usecwait(5);
5010393SSaurabh.Mishra@Sun.COM 		v = INL(atgep, ATGE_MDIO);
5110393SSaurabh.Mishra@Sun.COM 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
5210393SSaurabh.Mishra@Sun.COM 			break;
5310393SSaurabh.Mishra@Sun.COM 	}
5410393SSaurabh.Mishra@Sun.COM 
5510393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_mii_lock);
5610393SSaurabh.Mishra@Sun.COM 
5710393SSaurabh.Mishra@Sun.COM 	if (i == 0) {
5810393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "PHY (%d) read timeout : %d",
5910393SSaurabh.Mishra@Sun.COM 		    phy, reg);
6010393SSaurabh.Mishra@Sun.COM 
6110393SSaurabh.Mishra@Sun.COM 		return (0xffff);
6210393SSaurabh.Mishra@Sun.COM 	}
6310393SSaurabh.Mishra@Sun.COM 
6410518SSaurabh.Mishra@Sun.COM 	/*
6510518SSaurabh.Mishra@Sun.COM 	 * Some fast ethernet chips may not be able to auto-nego with
6610518SSaurabh.Mishra@Sun.COM 	 * switches even though they have 1000T based PHY. Hence we mask
6710518SSaurabh.Mishra@Sun.COM 	 * 1000T based capabilities.
6810518SSaurabh.Mishra@Sun.COM 	 */
6910518SSaurabh.Mishra@Sun.COM 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER) {
7010518SSaurabh.Mishra@Sun.COM 		if (reg == MII_STATUS)
7110518SSaurabh.Mishra@Sun.COM 			v &= ~MII_STATUS_EXTSTAT;
7210518SSaurabh.Mishra@Sun.COM 		else if (reg == MII_EXTSTATUS)
7310518SSaurabh.Mishra@Sun.COM 			v = 0;
7410518SSaurabh.Mishra@Sun.COM 	}
7510518SSaurabh.Mishra@Sun.COM 
7610393SSaurabh.Mishra@Sun.COM 	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
7710393SSaurabh.Mishra@Sun.COM }
7810393SSaurabh.Mishra@Sun.COM 
7910393SSaurabh.Mishra@Sun.COM void
atge_mii_write(void * arg,uint8_t phy,uint8_t reg,uint16_t val)8010393SSaurabh.Mishra@Sun.COM atge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
8110393SSaurabh.Mishra@Sun.COM {
8210393SSaurabh.Mishra@Sun.COM 	atge_t	*atgep = arg;
8310393SSaurabh.Mishra@Sun.COM 	uint32_t v;
8410393SSaurabh.Mishra@Sun.COM 	int i;
8510393SSaurabh.Mishra@Sun.COM 
8610393SSaurabh.Mishra@Sun.COM 	mutex_enter(&atgep->atge_mii_lock);
8710393SSaurabh.Mishra@Sun.COM 
8810393SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
8910393SSaurabh.Mishra@Sun.COM 	    (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT |
9010393SSaurabh.Mishra@Sun.COM 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
9110393SSaurabh.Mishra@Sun.COM 
9210393SSaurabh.Mishra@Sun.COM 	for (i = PHY_TIMEOUT; i > 0; i--) {
9310393SSaurabh.Mishra@Sun.COM 		drv_usecwait(1);
9410393SSaurabh.Mishra@Sun.COM 		v = INL(atgep, ATGE_MDIO);
9510393SSaurabh.Mishra@Sun.COM 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
9610393SSaurabh.Mishra@Sun.COM 			break;
9710393SSaurabh.Mishra@Sun.COM 	}
9810393SSaurabh.Mishra@Sun.COM 
9910393SSaurabh.Mishra@Sun.COM 	mutex_exit(&atgep->atge_mii_lock);
10010393SSaurabh.Mishra@Sun.COM 
10110393SSaurabh.Mishra@Sun.COM 	if (i == 0) {
10210393SSaurabh.Mishra@Sun.COM 		atge_error(atgep->atge_dip, "PHY (%d) write timeout:reg %d,"
10310393SSaurabh.Mishra@Sun.COM 		    "  val :%d", phy, reg, val);
10410393SSaurabh.Mishra@Sun.COM 	}
10510393SSaurabh.Mishra@Sun.COM }
10610393SSaurabh.Mishra@Sun.COM 
10710393SSaurabh.Mishra@Sun.COM void
atge_l1e_mii_reset(void * arg)10810393SSaurabh.Mishra@Sun.COM atge_l1e_mii_reset(void *arg)
10910393SSaurabh.Mishra@Sun.COM {
11010393SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
11110393SSaurabh.Mishra@Sun.COM 	int phyaddr;
11210393SSaurabh.Mishra@Sun.COM 
11310393SSaurabh.Mishra@Sun.COM 	phyaddr = mii_get_addr(atgep->atge_mii);
11410393SSaurabh.Mishra@Sun.COM 
115*11353SSaurabh.Mishra@Sun.COM 	OUTW(atgep, ATGE_GPHY_CTRL,
11610393SSaurabh.Mishra@Sun.COM 	    GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET |
11710393SSaurabh.Mishra@Sun.COM 	    GPHY_CTRL_PHY_PLL_ON);
11810393SSaurabh.Mishra@Sun.COM 	drv_usecwait(1000);
11910393SSaurabh.Mishra@Sun.COM 
120*11353SSaurabh.Mishra@Sun.COM 	OUTW(atgep, ATGE_GPHY_CTRL,
12110393SSaurabh.Mishra@Sun.COM 	    GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE |
12210393SSaurabh.Mishra@Sun.COM 	    GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_PLL_ON);
12310393SSaurabh.Mishra@Sun.COM 	drv_usecwait(1000);
12410393SSaurabh.Mishra@Sun.COM 
12510518SSaurabh.Mishra@Sun.COM 	/*
12610518SSaurabh.Mishra@Sun.COM 	 * Some fast ethernet chips may not be able to auto-nego with
12710518SSaurabh.Mishra@Sun.COM 	 * switches even though they have 1000T based PHY. Hence we need
12810518SSaurabh.Mishra@Sun.COM 	 * to write 0 to MII_MSCONTROL control register.
12910518SSaurabh.Mishra@Sun.COM 	 */
13010518SSaurabh.Mishra@Sun.COM 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER)
13110518SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, MII_MSCONTROL, 0x0);
13210518SSaurabh.Mishra@Sun.COM 
13310393SSaurabh.Mishra@Sun.COM 	/* Enable hibernation mode. */
13410393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0B);
13510393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0xBC00);
13610393SSaurabh.Mishra@Sun.COM 
13710393SSaurabh.Mishra@Sun.COM 	/* Set Class A/B for all modes. */
13810393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x00);
13910393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x02EF);
14010393SSaurabh.Mishra@Sun.COM 
14110393SSaurabh.Mishra@Sun.COM 	/* Enable 10BT power saving. */
14210393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x12);
14310393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x4C04);
14410393SSaurabh.Mishra@Sun.COM 
14510393SSaurabh.Mishra@Sun.COM 	/* Adjust 1000T power. */
14610393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x04);
14710393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x8BBB);
14810393SSaurabh.Mishra@Sun.COM 
14910393SSaurabh.Mishra@Sun.COM 	/* 10BT center tap voltage. */
15010393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x05);
15110393SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x2C46);
15210393SSaurabh.Mishra@Sun.COM 	drv_usecwait(1000);
15310393SSaurabh.Mishra@Sun.COM }
154*11353SSaurabh.Mishra@Sun.COM 
155*11353SSaurabh.Mishra@Sun.COM void
atge_l1_mii_reset(void * arg)156*11353SSaurabh.Mishra@Sun.COM atge_l1_mii_reset(void *arg)
157*11353SSaurabh.Mishra@Sun.COM {
158*11353SSaurabh.Mishra@Sun.COM 	atge_t *atgep = arg;
159*11353SSaurabh.Mishra@Sun.COM 	int linkup, i;
160*11353SSaurabh.Mishra@Sun.COM 	uint16_t reg, pn;
161*11353SSaurabh.Mishra@Sun.COM 	int phyaddr;
162*11353SSaurabh.Mishra@Sun.COM 
163*11353SSaurabh.Mishra@Sun.COM 	phyaddr = mii_get_addr(atgep->atge_mii);
164*11353SSaurabh.Mishra@Sun.COM 
165*11353SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_GPHY_CTRL, GPHY_CTRL_RST);
166*11353SSaurabh.Mishra@Sun.COM 	drv_usecwait(1000);
167*11353SSaurabh.Mishra@Sun.COM 
168*11353SSaurabh.Mishra@Sun.COM 	OUTL(atgep, ATGE_GPHY_CTRL, GPHY_CTRL_CLR);
169*11353SSaurabh.Mishra@Sun.COM 	drv_usecwait(1000);
170*11353SSaurabh.Mishra@Sun.COM 
171*11353SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, MII_CONTROL, MII_CONTROL_RESET);
172*11353SSaurabh.Mishra@Sun.COM 
173*11353SSaurabh.Mishra@Sun.COM 	for (linkup = 0, pn = 0; pn < 4; pn++) {
174*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_CDTC,
175*11353SSaurabh.Mishra@Sun.COM 		    (pn << PHY_CDTC_POFF) | PHY_CDTC_ENB);
176*11353SSaurabh.Mishra@Sun.COM 
177*11353SSaurabh.Mishra@Sun.COM 		for (i = 200; i > 0; i--) {
178*11353SSaurabh.Mishra@Sun.COM 			drv_usecwait(1000);
179*11353SSaurabh.Mishra@Sun.COM 
180*11353SSaurabh.Mishra@Sun.COM 			reg = atge_mii_read(atgep, phyaddr, ATPHY_CDTC);
181*11353SSaurabh.Mishra@Sun.COM 
182*11353SSaurabh.Mishra@Sun.COM 			if ((reg & PHY_CDTC_ENB) == 0)
183*11353SSaurabh.Mishra@Sun.COM 				break;
184*11353SSaurabh.Mishra@Sun.COM 		}
185*11353SSaurabh.Mishra@Sun.COM 
186*11353SSaurabh.Mishra@Sun.COM 		drv_usecwait(1000);
187*11353SSaurabh.Mishra@Sun.COM 
188*11353SSaurabh.Mishra@Sun.COM 		reg = atge_mii_read(atgep, phyaddr, ATPHY_CDTS);
189*11353SSaurabh.Mishra@Sun.COM 
190*11353SSaurabh.Mishra@Sun.COM 		if ((reg & PHY_CDTS_STAT_MASK) != PHY_CDTS_STAT_OPEN) {
191*11353SSaurabh.Mishra@Sun.COM 			linkup++;
192*11353SSaurabh.Mishra@Sun.COM 			break;
193*11353SSaurabh.Mishra@Sun.COM 		}
194*11353SSaurabh.Mishra@Sun.COM 	}
195*11353SSaurabh.Mishra@Sun.COM 
196*11353SSaurabh.Mishra@Sun.COM 	atge_mii_write(atgep, phyaddr, MII_CONTROL,
197*11353SSaurabh.Mishra@Sun.COM 	    MII_CONTROL_RESET |  MII_CONTROL_ANE | MII_CONTROL_RSAN);
198*11353SSaurabh.Mishra@Sun.COM 
199*11353SSaurabh.Mishra@Sun.COM 	if (linkup == 0) {
200*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0);
201*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x124E);
202*11353SSaurabh.Mishra@Sun.COM 
203*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 1);
204*11353SSaurabh.Mishra@Sun.COM 		reg = atge_mii_read(atgep, phyaddr, ATPHY_DBG_DATA);
205*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, reg | 0x03);
206*11353SSaurabh.Mishra@Sun.COM 
207*11353SSaurabh.Mishra@Sun.COM 		drv_usecwait(1500 * 1000);
208*11353SSaurabh.Mishra@Sun.COM 
209*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0);
210*11353SSaurabh.Mishra@Sun.COM 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x024E);
211*11353SSaurabh.Mishra@Sun.COM 	}
212*11353SSaurabh.Mishra@Sun.COM }
213