• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute  it and/or modify it
5  * under  the terms of  the GNU General  Public License as published by the
6  * Free Software Foundation;  either version 2 of the  License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Description: hieth mii operation
18  */
19 
20 
21 #include "hieth.h"
22 #include "mdio.h"
23 #include "mii_drv.h"
24 #include <config.h>
25 
26 /* MDIO Bus Interface */
hieth_mdiobus_read(struct mii_dev * bus,int addr,int devad,int reg)27 static int hieth_mdiobus_read(struct mii_dev *bus, int addr, int devad, int reg)
28 {
29 	struct hieth_netdev_local *ld = (struct hieth_netdev_local *)bus->priv;
30 
31 	return hieth_mdio_read(ld, addr, reg);
32 }
33 
hieth_mdiobus_write(struct mii_dev * bus,int addr,int devad,int reg,u16 value)34 static int hieth_mdiobus_write(struct mii_dev *bus, int addr, int devad,
35 		  int reg, u16 value)
36 {
37 	struct hieth_netdev_local *ld = (struct hieth_netdev_local *)bus->priv;
38 
39 	hieth_mdio_write(ld, addr, reg, value);
40 
41 	return 0;
42 }
43 
44 #define PHY_ID_KSZ8051 0x00221550
45 #define PHY_ID_KSZ8081 0x00221560
46 #define PHY_ID_MASK    0xFFFFFFF0
47 
get_fephy_id(const char * devname,unsigned char phyaddr,u32 * phy_id)48 static bool get_fephy_id(const char *devname, unsigned char phyaddr, u32 *phy_id)
49 {
50 	u16 id1 = 0;
51 	u16 id2 = 0;
52 
53 	if (miiphy_read(devname, phyaddr, MII_PHYSID1, &id1)) {
54 		printf("%s,%d:PHY_PHYIDR1 read failed!\n", __func__, __LINE__);
55 		return false;
56 	}
57 	if (miiphy_read(devname, phyaddr, MII_PHYSID2, &id2)) {
58 		printf("%s,%d:PHY_PHYIDR2 read failed!\n", __func__, __LINE__);
59 		return false;
60 	}
61 
62 	*phy_id = (id1 & 0xffff) << 16; /* high 16 bit */
63 	*phy_id |= (id2 & 0xffff);
64 
65 	/* If the phy_id is all Fs, there is no device there */
66 	if (*phy_id == 0xffffffff || *phy_id == 0 || *phy_id == 0xFFFF || *phy_id == 0xFFFF0000) {
67 		return false;
68 	}
69 
70 	return true;
71 }
72 
phy_detected(const char * devname,unsigned char phyaddr)73 bool phy_detected(const char *devname, unsigned char phyaddr)
74 {
75 	u32 phy_id = 0;
76 
77 	if (!get_fephy_id(devname, phyaddr, &phy_id)) return false;
78 
79 	/* run this at RMII mode */
80 	if (HIETH_MII_RMII_MODE_U == 1) {
81 		/* PHY-KSZ8051RNL */
82 		if ((phy_id & PHY_ID_MASK) == PHY_ID_KSZ8051) {
83 			unsigned short reg = 0;
84 
85 			if (miiphy_read(devname, phyaddr, 0x1F, &reg)) {
86 				printf("PHY 0x1F read failed\n");
87 				return false;
88 			}
89 			reg |= bit(7); /* bit7:set phy RMII 50MHz clk; */
90 			if (miiphy_write(devname, phyaddr, 0x1F, reg)) {
91 				printf("PHY 0x1F write failed\n");
92 				return false;
93 			}
94 
95 			if (miiphy_read(devname, phyaddr, 0x16, &reg)) {
96 				printf("PHY 0x16 read failed\n");
97 				return false;
98 			}
99 			reg |= bit(1); /* set phy RMII override; */
100 			if (miiphy_write(devname, phyaddr, 0x16, reg)) {
101 				printf("PHY 0x16 write failed\n");
102 				return false;
103 			}
104 		}
105 
106 		/* PHY-KSZ8081 */
107 		if ((phy_id & PHY_ID_MASK) == PHY_ID_KSZ8081) {
108 			unsigned short val = 0;
109 
110 			if (miiphy_read(devname, phyaddr, 0x1F, &val) != 0) {
111 				printf("PHY 0x1F read failed\n");
112 				return false;
113 			};
114 			val |= bit(7); /* bit7:set phy RMII 50MHz clk; */
115 			if (miiphy_write(devname, phyaddr, 0x1F, val) != 0) {
116 				printf("PHY 0x1F write failed\n");
117 				return false;
118 			}
119 		}
120 	}
121 	return true;
122 }
123 
124 static int g_mdio_registered;
125 
hieth_mdiobus_driver_init(struct hieth_netdev_local * ld)126 int hieth_mdiobus_driver_init(struct hieth_netdev_local *ld)
127 {
128 	memset(ld->mii_name, 0, MAX_PHY_NAME_LEN);
129 	snprintf(ld->mii_name, MAX_PHY_NAME_LEN, "mii_hieth");
130 	ld->mdio_frqdiv = ETH_MDIO_FRQDIV;
131 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
132 	if (!g_mdio_registered) {
133 		struct mii_dev *bus = mdio_alloc();
134 
135 		if (!bus) {
136 			printf("Failed to allocate MDIO bus\n");
137 			return -ENOMEM;
138 		}
139 
140 		bus->priv = ld;
141 		bus->read = hieth_mdiobus_read;
142 		bus->write = hieth_mdiobus_write;
143 		snprintf(bus->name, sizeof(bus->name), ld->mii_name);
144 
145 		hieth_mdio_init(ld);
146 
147 		if (mdio_register(bus)) {
148 			mdio_free(bus);
149 			return -1;
150 		}
151 
152 		miiphy_set_current_dev(ld->mii_name);
153 		g_mdio_registered = 1;
154 	}
155 #endif
156 	return 0;
157 }
158 
hieth_mdiobus_driver_exit(struct hieth_netdev_local * ld)159 void hieth_mdiobus_driver_exit(struct hieth_netdev_local *ld)
160 {
161 	/* add this to avoid the first time to use eth will print 'No such device: XXXXX' message. */
162 	if (!miiphy_get_current_dev()) {
163 		return;
164 	}
165 
166 	hieth_mdio_exit(ld);
167 }
168