xref: /openbmc/u-boot/drivers/net/phy/et1011c.c (revision f485c8a35b38356a473208bec5ed786792c1eafe)
1*f485c8a3SMatt Porter /*
2*f485c8a3SMatt Porter  * ET1011C PHY driver
3*f485c8a3SMatt Porter  *
4*f485c8a3SMatt Porter  * Derived from Linux kernel driver by Chaithrika U S
5*f485c8a3SMatt Porter  * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
6*f485c8a3SMatt Porter  *
7*f485c8a3SMatt Porter  * This program is free software; you can redistribute it and/or
8*f485c8a3SMatt Porter  * modify it under the terms of the GNU General Public License as
9*f485c8a3SMatt Porter  * published by the Free Software Foundation; either version 2 of
10*f485c8a3SMatt Porter  * the License, or (at your option) any later version.
11*f485c8a3SMatt Porter  *
12*f485c8a3SMatt Porter  * This program is distributed in the hope that it will be useful,
13*f485c8a3SMatt Porter  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*f485c8a3SMatt Porter  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*f485c8a3SMatt Porter  * GNU General Public License for more details.
16*f485c8a3SMatt Porter  *
17*f485c8a3SMatt Porter  */
18*f485c8a3SMatt Porter #include <config.h>
19*f485c8a3SMatt Porter #include <phy.h>
20*f485c8a3SMatt Porter 
21*f485c8a3SMatt Porter #define ET1011C_CONFIG_REG		(0x16)
22*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_MASK		(0x3 << 12)
23*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_8		(0x0 << 12)
24*f485c8a3SMatt Porter #define ET1011C_TX_FIFO_DEPTH_16	(0x1 << 12)
25*f485c8a3SMatt Porter #define ET1011C_INTERFACE_MASK		(0x7 << 0)
26*f485c8a3SMatt Porter #define ET1011C_GMII_INTERFACE		(0x2 << 0)
27*f485c8a3SMatt Porter #define ET1011C_SYS_CLK_EN		(0x1 << 4)
28*f485c8a3SMatt Porter #define ET1011C_TX_CLK_EN		(0x1 << 5)
29*f485c8a3SMatt Porter 
30*f485c8a3SMatt Porter #define ET1011C_STATUS_REG		(0x1A)
31*f485c8a3SMatt Porter #define ET1011C_DUPLEX_STATUS		(0x1 << 7)
32*f485c8a3SMatt Porter #define ET1011C_SPEED_MASK		(0x3 << 8)
33*f485c8a3SMatt Porter #define ET1011C_SPEED_1000		(0x2 << 8)
34*f485c8a3SMatt Porter #define ET1011C_SPEED_100		(0x1 << 8)
35*f485c8a3SMatt Porter #define ET1011C_SPEED_10		(0x0 << 8)
36*f485c8a3SMatt Porter 
37*f485c8a3SMatt Porter static int et1011c_config(struct phy_device *phydev)
38*f485c8a3SMatt Porter {
39*f485c8a3SMatt Porter 	int ctl = 0;
40*f485c8a3SMatt Porter 	ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
41*f485c8a3SMatt Porter 	if (ctl < 0)
42*f485c8a3SMatt Porter 		return ctl;
43*f485c8a3SMatt Porter 	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
44*f485c8a3SMatt Porter 		 BMCR_ANENABLE);
45*f485c8a3SMatt Porter 	/* First clear the PHY */
46*f485c8a3SMatt Porter 	phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET);
47*f485c8a3SMatt Porter 
48*f485c8a3SMatt Porter 	return genphy_config_aneg(phydev);
49*f485c8a3SMatt Porter }
50*f485c8a3SMatt Porter 
51*f485c8a3SMatt Porter static int et1011c_parse_status(struct phy_device *phydev)
52*f485c8a3SMatt Porter {
53*f485c8a3SMatt Porter 	int mii_reg;
54*f485c8a3SMatt Porter 	int speed;
55*f485c8a3SMatt Porter 
56*f485c8a3SMatt Porter 	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_STATUS_REG);
57*f485c8a3SMatt Porter 
58*f485c8a3SMatt Porter 	if (mii_reg & ET1011C_DUPLEX_STATUS)
59*f485c8a3SMatt Porter 		phydev->duplex = DUPLEX_FULL;
60*f485c8a3SMatt Porter 	else
61*f485c8a3SMatt Porter 		phydev->duplex = DUPLEX_HALF;
62*f485c8a3SMatt Porter 
63*f485c8a3SMatt Porter 	speed = mii_reg & ET1011C_SPEED_MASK;
64*f485c8a3SMatt Porter 	switch (speed) {
65*f485c8a3SMatt Porter 	case ET1011C_SPEED_1000:
66*f485c8a3SMatt Porter 		phydev->speed = SPEED_1000;
67*f485c8a3SMatt Porter 		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG);
68*f485c8a3SMatt Porter 		mii_reg &= ~ET1011C_TX_FIFO_MASK;
69*f485c8a3SMatt Porter 		phy_write(phydev, MDIO_DEVAD_NONE, ET1011C_CONFIG_REG,
70*f485c8a3SMatt Porter 			  mii_reg |
71*f485c8a3SMatt Porter 			  ET1011C_GMII_INTERFACE |
72*f485c8a3SMatt Porter 			  ET1011C_SYS_CLK_EN |
73*f485c8a3SMatt Porter #ifdef CONFIG_PHY_ET1011C_TX_CLK_FIX
74*f485c8a3SMatt Porter 			  ET1011C_TX_CLK_EN |
75*f485c8a3SMatt Porter #endif
76*f485c8a3SMatt Porter 			  ET1011C_TX_FIFO_DEPTH_16);
77*f485c8a3SMatt Porter 		break;
78*f485c8a3SMatt Porter 	case ET1011C_SPEED_100:
79*f485c8a3SMatt Porter 		phydev->speed = SPEED_100;
80*f485c8a3SMatt Porter 		break;
81*f485c8a3SMatt Porter 	case ET1011C_SPEED_10:
82*f485c8a3SMatt Porter 		phydev->speed = SPEED_10;
83*f485c8a3SMatt Porter 		break;
84*f485c8a3SMatt Porter 	}
85*f485c8a3SMatt Porter 
86*f485c8a3SMatt Porter 	return 0;
87*f485c8a3SMatt Porter }
88*f485c8a3SMatt Porter 
89*f485c8a3SMatt Porter static int et1011c_startup(struct phy_device *phydev)
90*f485c8a3SMatt Porter {
91*f485c8a3SMatt Porter 	genphy_update_link(phydev);
92*f485c8a3SMatt Porter 	et1011c_parse_status(phydev);
93*f485c8a3SMatt Porter 	return 0;
94*f485c8a3SMatt Porter }
95*f485c8a3SMatt Porter 
96*f485c8a3SMatt Porter static struct phy_driver et1011c_driver = {
97*f485c8a3SMatt Porter 	.name		= "ET1011C",
98*f485c8a3SMatt Porter 	.uid		= 0x0282f014,
99*f485c8a3SMatt Porter 	.mask		= 0xfffffff0,
100*f485c8a3SMatt Porter 	.features	= PHY_GBIT_FEATURES,
101*f485c8a3SMatt Porter 	.config		= &et1011c_config,
102*f485c8a3SMatt Porter 	.startup	= &et1011c_startup,
103*f485c8a3SMatt Porter };
104*f485c8a3SMatt Porter 
105*f485c8a3SMatt Porter int phy_et1011c_init(void)
106*f485c8a3SMatt Porter {
107*f485c8a3SMatt Porter 	phy_register(&et1011c_driver);
108*f485c8a3SMatt Porter 
109*f485c8a3SMatt Porter 	return 0;
110*f485c8a3SMatt Porter }
111