1 /*
2  * (C) Copyright 2006
3  * Author : Eric Benard (Eukrea Electromatique)
4  * based on dm9161.c which is :
5  * (C) Copyright 2003
6  * Author : Hamid Ikdoumi (Atmel)
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26 
27 #include <at91rm9200_net.h>
28 #include <net.h>
29 #include <ks8721.h>
30 
31 #ifdef CONFIG_DRIVER_ETHER
32 
33 #if defined(CONFIG_CMD_NET)
34 
35 /*
36  * Name:
37  *	ks8721_isphyconnected
38  * Description:
39  *	Reads the 2 PHY ID registers
40  * Arguments:
41  *	p_mac - pointer to AT91S_EMAC struct
42  * Return value:
43  *	1 - if id read successfully
44  *	0 - if error
45  */
ks8721_isphyconnected(AT91PS_EMAC p_mac)46 unsigned int ks8721_isphyconnected(AT91PS_EMAC p_mac)
47 {
48 	unsigned short id1, id2;
49 
50 	at91rm9200_EmacEnableMDIO(p_mac);
51 	at91rm9200_EmacReadPhy(p_mac,
52 		CONFIG_PHY_ADDRESS | KS8721_PHYID1, &id1);
53 	at91rm9200_EmacReadPhy(p_mac,
54 		CONFIG_PHY_ADDRESS | KS8721_PHYID2, &id2);
55 	at91rm9200_EmacDisableMDIO(p_mac);
56 
57 	if ((id1 == (KS8721_PHYID_OUI >> 6)) &&
58 		((id2 >> 10) == (KS8721_PHYID_OUI & KS8721_LSB_MASK))) {
59 		if ((id2 & KS8721_MODELMASK) == KS8721BL_MODEL)
60 			printf("Micrel KS8721bL PHY detected : ");
61 		else
62 			printf("Unknown Micrel PHY detected : ");
63 		return 1;
64 	}
65 	return 0;
66 }
67 
68 /*
69  * Name:
70  *	ks8721_getlinkspeed
71  * Description:
72  *	Link parallel detection status of MAC is checked and set in the
73  *	MAC configuration registers
74  * Arguments:
75  *	p_mac - pointer to MAC
76  * Return value:
77  *	1 - if link status set succesfully
78  *	0 - if link status not set
79  */
ks8721_getlinkspeed(AT91PS_EMAC p_mac)80 unsigned char ks8721_getlinkspeed(AT91PS_EMAC p_mac)
81 {
82 	unsigned short stat1;
83 
84 	if (!at91rm9200_EmacReadPhy(p_mac, KS8721_BMSR, &stat1))
85 		return 0;
86 
87 	if (!(stat1 & KS8721_LINK_STATUS)) {
88 		/* link status up? */
89 		printf("Link Down !\n");
90 		return 0;
91 	}
92 
93 	if (stat1 & KS8721_100BASE_TX_FD) {
94 		/* set Emac for 100BaseTX and Full Duplex */
95 		printf("100BT FD\n");
96 		p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;
97 		return 1;
98 	}
99 
100 	if (stat1 & KS8721_10BASE_T_FD) {
101 		/* set MII for 10BaseT and Full Duplex */
102 		printf("10BT FD\n");
103 		p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
104 				~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
105 				| AT91C_EMAC_FD;
106 		return 1;
107 	}
108 
109 	if (stat1 & KS8721_100BASE_T4_HD) {
110 		/* set MII for 100BaseTX and Half Duplex */
111 		printf("100BT HD\n");
112 		p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
113 				~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
114 				| AT91C_EMAC_SPD;
115 		return 1;
116 	}
117 
118 	if (stat1 & KS8721_10BASE_T_HD) {
119 		/* set MII for 10BaseT and Half Duplex */
120 		printf("10BT HD\n");
121 		p_mac->EMAC_CFG &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
122 		return 1;
123 	}
124 	return 0;
125 }
126 
127 /*
128  * Name:
129  *	ks8721_initphy
130  * Description:
131  *	MAC starts checking its link by using parallel detection and
132  *	Autonegotiation and the same is set in the MAC configuration registers
133  * Arguments:
134  *	p_mac - pointer to struct AT91S_EMAC
135  * Return value:
136  *	1 - if link status set succesfully
137  *	0 - if link status not set
138  */
ks8721_initphy(AT91PS_EMAC p_mac)139 unsigned char ks8721_initphy(AT91PS_EMAC p_mac)
140 {
141 	unsigned char ret = 1;
142 	unsigned short intvalue;
143 
144 	at91rm9200_EmacEnableMDIO(p_mac);
145 
146 	/* Try another time */
147 	if (!ks8721_getlinkspeed(p_mac))
148 		ret = ks8721_getlinkspeed(p_mac);
149 
150 	/* Disable PHY Interrupts */
151 	intvalue = 0;
152 	at91rm9200_EmacWritePhy(p_mac,
153 		CONFIG_PHY_ADDRESS | KS8721_MDINTR, &intvalue);
154 	at91rm9200_EmacDisableMDIO(p_mac);
155 
156 	return ret;
157 }
158 
159 /*
160  * Name:
161  *	ks8721_autonegotiate
162  * Description:
163  *	MAC Autonegotiates with the partner status of same is set in the
164  *	MAC configuration registers
165  * Arguments:
166  *	dev - pointer to struct net_device
167  * Return value:
168  *	1 - if link status set successfully
169  *	0 - if link status not set
170  */
ks8721_autonegotiate(AT91PS_EMAC p_mac,int * status)171 unsigned char ks8721_autonegotiate(AT91PS_EMAC p_mac, int *status)
172 {
173 	unsigned short value;
174 	unsigned short phyanar;
175 	unsigned short phyanalpar;
176 
177 	/* Set ks8721 control register */
178 	if (!at91rm9200_EmacReadPhy(p_mac,
179 		CONFIG_PHY_ADDRESS | KS8721_BMCR, &value))
180 		return 0;
181 
182 	/* remove autonegotiation enable */
183 	value &= ~KS8721_AUTONEG;
184 	/* Electrically isolate PHY */
185 	value |= KS8721_ISOLATE;
186 	if (!at91rm9200_EmacWritePhy(p_mac,
187 		CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
188 		return 0;
189 	}
190 	/*
191 	 * Set the Auto_negotiation Advertisement Register
192 	 * MII advertising for Next page, 100BaseTxFD and HD,
193 	 * 10BaseTFD and HD, IEEE 802.3
194 	 */
195 	phyanar = KS8721_NP | KS8721_TX_FDX | KS8721_TX_HDX |
196 		  KS8721_10_FDX | KS8721_10_HDX | KS8721_AN_IEEE_802_3;
197 	if (!at91rm9200_EmacWritePhy(p_mac,
198 		CONFIG_PHY_ADDRESS | KS8721_ANAR, &phyanar)) {
199 		return 0;
200 	}
201 	/* Read the Control Register */
202 	if (!at91rm9200_EmacReadPhy(p_mac,
203 		CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
204 		return 0;
205 	}
206 	value |= KS8721_SPEED_SELECT | KS8721_AUTONEG | KS8721_DUPLEX_MODE;
207 	if (!at91rm9200_EmacWritePhy(p_mac,
208 		CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
209 		return 0;
210 	}
211 	/* Restart Auto_negotiation */
212 	value |= KS8721_RESTART_AUTONEG;
213 	value &= ~KS8721_ISOLATE;
214 	if (!at91rm9200_EmacWritePhy(p_mac,
215 		CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
216 		return 0;
217 	}
218 	/* Check AutoNegotiate complete */
219 	udelay(10000);
220 	at91rm9200_EmacReadPhy(p_mac,
221 		CONFIG_PHY_ADDRESS | KS8721_BMSR, &value);
222 	if (!(value & KS8721_AUTONEG_COMP))
223 		return 0;
224 
225 	/* Get the AutoNeg Link partner base page */
226 	if (!at91rm9200_EmacReadPhy(p_mac,
227 		CONFIG_PHY_ADDRESS | KS8721_ANLPAR, &phyanalpar)) {
228 		return 0;
229 	}
230 
231 	if ((phyanar & KS8721_TX_FDX) && (phyanalpar & KS8721_TX_FDX)) {
232 		/* Set MII for 100BaseTX and Full Duplex */
233 		p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;
234 		return 1;
235 	}
236 
237 	if ((phyanar & KS8721_10_FDX) && (phyanalpar & KS8721_10_FDX)) {
238 		/* Set MII for 10BaseT and Full Duplex */
239 		p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
240 				~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
241 				| AT91C_EMAC_FD;
242 		return 1;
243 	}
244 	return 0;
245 }
246 
247 #endif	/* CONFIG_CMD_NET */
248 
249 #endif	/* CONFIG_DRIVER_ETHER */
250