xref: /illumos-gate/usr/src/uts/common/io/atge/atge_mii.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 	return ((v & MDIO_DATA_MASK) >> MDIO_DATA_SHIFT);
64 }
65 
66 void
67 atge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
68 {
69 	atge_t	*atgep = arg;
70 	uint32_t v;
71 	int i;
72 
73 	mutex_enter(&atgep->atge_mii_lock);
74 
75 	OUTL(atgep, ATGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE |
76 	    (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT |
77 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
78 
79 	for (i = PHY_TIMEOUT; i > 0; i--) {
80 		drv_usecwait(1);
81 		v = INL(atgep, ATGE_MDIO);
82 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
83 			break;
84 	}
85 
86 	mutex_exit(&atgep->atge_mii_lock);
87 
88 	if (i == 0) {
89 		atge_error(atgep->atge_dip, "PHY (%d) write timeout:reg %d,"
90 		    "  val :%d", phy, reg, val);
91 	}
92 }
93 
94 void
95 atge_l1e_mii_reset(void *arg)
96 {
97 	atge_t *atgep = arg;
98 	int phyaddr;
99 
100 	phyaddr = mii_get_addr(atgep->atge_mii);
101 
102 	OUTW(atgep, L1E_GPHY_CTRL,
103 	    GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET |
104 	    GPHY_CTRL_PHY_PLL_ON);
105 	drv_usecwait(1000);
106 
107 	OUTW(atgep, L1E_GPHY_CTRL,
108 	    GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE |
109 	    GPHY_CTRL_SEL_ANA_RESET | GPHY_CTRL_PHY_PLL_ON);
110 	drv_usecwait(1000);
111 
112 	/* Enable hibernation mode. */
113 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0B);
114 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0xBC00);
115 
116 	/* Set Class A/B for all modes. */
117 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x00);
118 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x02EF);
119 
120 	/* Enable 10BT power saving. */
121 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x12);
122 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x4C04);
123 
124 	/* Adjust 1000T power. */
125 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x04);
126 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x8BBB);
127 
128 	/* 10BT center tap voltage. */
129 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x05);
130 	atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x2C46);
131 	drv_usecwait(1000);
132 }
133