xref: /illumos-gate/usr/src/uts/common/io/atge/atge_mii.c (revision 635216b673cf196ac523ff2a7ab715717e553292)
1 /*
2  * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/mii.h>
29 #include <sys/miiregs.h>
30 
31 #include "atge.h"
32 #include "atge_cmn_reg.h"
33 #include "atge_l1e_reg.h"
34 
35 uint16_t
36 atge_mii_read(void *arg, uint8_t phy, uint8_t reg)
37 {
38 	atge_t	*atgep = arg;
39 	uint32_t v;
40 	int i;
41 
42 	mutex_enter(&atgep->atge_mii_lock);
43 
44 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ |
45 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
46 
47 	for (i = PHY_TIMEOUT; i > 0; i--) {
48 		drv_usecwait(5);
49 		v = INL(atgep, ATGE_MDIO);
50 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
51 			break;
52 	}
53 
54 	mutex_exit(&atgep->atge_mii_lock);
55 
56 	if (i == 0) {
57 		atge_error(atgep->atge_dip, "PHY (%d) read timeout : %d",
58 		    phy, reg);
59 
60 		return (0xffff);
61 	}
62 
63 	/*
64 	 * Some fast ethernet chips may not be able to auto-nego with
65 	 * switches even though they have 1000T based PHY. Hence we mask
66 	 * 1000T based capabilities.
67 	 */
68 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER) {
69 		if (reg == MII_STATUS)
70 			v &= ~MII_STATUS_EXTSTAT;
71 		else if (reg == MII_EXTSTATUS)
72 			v = 0;
73 	}
74 
75 	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
76 }
77 
78 void
79 atge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
80 {
81 	atge_t	*atgep = arg;
82 	uint32_t v;
83 	int i;
84 
85 	mutex_enter(&atgep->atge_mii_lock);
86 
87 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
88 	    (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT |
89 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
90 
91 	for (i = PHY_TIMEOUT; i > 0; i--) {
92 		drv_usecwait(1);
93 		v = INL(atgep, ATGE_MDIO);
94 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
95 			break;
96 	}
97 
98 	mutex_exit(&atgep->atge_mii_lock);
99 
100 	if (i == 0) {
101 		atge_error(atgep->atge_dip, "PHY (%d) write timeout:reg %d,"
102 		    "  val :%d", phy, reg, val);
103 	}
104 }
105 
106 void
107 atge_l1e_mii_reset(void *arg)
108 {
109 	atge_t *atgep = arg;
110 	int phyaddr;
111 
112 	phyaddr = mii_get_addr(atgep->atge_mii);
113 
114 	OUTW(atgep, L1E_GPHY_CTRL,
115 	    GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET |
116 	    GPHY_CTRL_PHY_PLL_ON);
117 	drv_usecwait(1000);
118 
119 	OUTW(atgep, L1E_GPHY_CTRL,
120 	    GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE |
121 	    GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_PLL_ON);
122 	drv_usecwait(1000);
123 
124 	/*
125 	 * Some fast ethernet chips may not be able to auto-nego with
126 	 * switches even though they have 1000T based PHY. Hence we need
127 	 * to write 0 to MII_MSCONTROL control register.
128 	 */
129 	if (atgep->atge_flags & ATGE_FLAG_FASTETHER)
130 		atge_mii_write(atgep, phyaddr, MII_MSCONTROL, 0x0);
131 
132 	/* Enable hibernation mode. */
133 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0B);
134 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0xBC00);
135 
136 	/* Set Class A/B for all modes. */
137 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x00);
138 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x02EF);
139 
140 	/* Enable 10BT power saving. */
141 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x12);
142 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x4C04);
143 
144 	/* Adjust 1000T power. */
145 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x04);
146 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x8BBB);
147 
148 	/* 10BT center tap voltage. */
149 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x05);
150 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x2C46);
151 	drv_usecwait(1000);
152 }
153