xref: /OK3568_Linux_fs/u-boot/drivers/net/phy/micrel_ksz90x1.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Micrel PHY drivers
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2010-2011 Freescale Semiconductor, Inc.
7*4882a593Smuzhiyun  * author Andy Fleming
8*4882a593Smuzhiyun  * (C) 2012 NetModule AG, David Andrey, added KSZ9031
9*4882a593Smuzhiyun  * (C) Copyright 2017 Adaptrum, Inc.
10*4882a593Smuzhiyun  * Written by Alexandru Gagniuc <alex.g@adaptrum.com> for Adaptrum, Inc.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <config.h>
14*4882a593Smuzhiyun #include <common.h>
15*4882a593Smuzhiyun #include <dm.h>
16*4882a593Smuzhiyun #include <errno.h>
17*4882a593Smuzhiyun #include <micrel.h>
18*4882a593Smuzhiyun #include <phy.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * KSZ9021 - KSZ9031 common
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define MII_KSZ90xx_PHY_CTL		0x1f
27*4882a593Smuzhiyun #define MIIM_KSZ90xx_PHYCTL_1000	(1 << 6)
28*4882a593Smuzhiyun #define MIIM_KSZ90xx_PHYCTL_100		(1 << 5)
29*4882a593Smuzhiyun #define MIIM_KSZ90xx_PHYCTL_10		(1 << 4)
30*4882a593Smuzhiyun #define MIIM_KSZ90xx_PHYCTL_DUPLEX	(1 << 3)
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* KSZ9021 PHY Registers */
33*4882a593Smuzhiyun #define MII_KSZ9021_EXTENDED_CTRL	0x0b
34*4882a593Smuzhiyun #define MII_KSZ9021_EXTENDED_DATAW	0x0c
35*4882a593Smuzhiyun #define MII_KSZ9021_EXTENDED_DATAR	0x0d
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define CTRL1000_PREFER_MASTER		(1 << 10)
38*4882a593Smuzhiyun #define CTRL1000_CONFIG_MASTER		(1 << 11)
39*4882a593Smuzhiyun #define CTRL1000_MANUAL_CONFIG		(1 << 12)
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /* KSZ9031 PHY Registers */
42*4882a593Smuzhiyun #define MII_KSZ9031_MMD_ACCES_CTRL	0x0d
43*4882a593Smuzhiyun #define MII_KSZ9031_MMD_REG_DATA	0x0e
44*4882a593Smuzhiyun 
ksz90xx_startup(struct phy_device * phydev)45*4882a593Smuzhiyun static int ksz90xx_startup(struct phy_device *phydev)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	unsigned phy_ctl;
48*4882a593Smuzhiyun 	int ret;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	ret = genphy_update_link(phydev);
51*4882a593Smuzhiyun 	if (ret)
52*4882a593Smuzhiyun 		return ret;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
57*4882a593Smuzhiyun 		phydev->duplex = DUPLEX_FULL;
58*4882a593Smuzhiyun 	else
59*4882a593Smuzhiyun 		phydev->duplex = DUPLEX_HALF;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
62*4882a593Smuzhiyun 		phydev->speed = SPEED_1000;
63*4882a593Smuzhiyun 	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
64*4882a593Smuzhiyun 		phydev->speed = SPEED_100;
65*4882a593Smuzhiyun 	else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
66*4882a593Smuzhiyun 		phydev->speed = SPEED_10;
67*4882a593Smuzhiyun 	return 0;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* Common OF config bits for KSZ9021 and KSZ9031 */
71*4882a593Smuzhiyun #ifdef CONFIG_DM_ETH
72*4882a593Smuzhiyun struct ksz90x1_reg_field {
73*4882a593Smuzhiyun 	const char	*name;
74*4882a593Smuzhiyun 	const u8	size;	/* Size of the bitfield, in bits */
75*4882a593Smuzhiyun 	const u8	off;	/* Offset from bit 0 */
76*4882a593Smuzhiyun 	const u8	dflt;	/* Default value */
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun struct ksz90x1_ofcfg {
80*4882a593Smuzhiyun 	const u16			reg;
81*4882a593Smuzhiyun 	const u16			devad;
82*4882a593Smuzhiyun 	const struct ksz90x1_reg_field	*grp;
83*4882a593Smuzhiyun 	const u16			grpsz;
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static const struct ksz90x1_reg_field ksz90x1_rxd_grp[] = {
87*4882a593Smuzhiyun 	{ "rxd0-skew-ps", 4, 0, 0x7 }, { "rxd1-skew-ps", 4, 4, 0x7 },
88*4882a593Smuzhiyun 	{ "rxd2-skew-ps", 4, 8, 0x7 }, { "rxd3-skew-ps", 4, 12, 0x7 }
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static const struct ksz90x1_reg_field ksz90x1_txd_grp[] = {
92*4882a593Smuzhiyun 	{ "txd0-skew-ps", 4, 0, 0x7 }, { "txd1-skew-ps", 4, 4, 0x7 },
93*4882a593Smuzhiyun 	{ "txd2-skew-ps", 4, 8, 0x7 }, { "txd3-skew-ps", 4, 12, 0x7 },
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun static const struct ksz90x1_reg_field ksz9021_clk_grp[] = {
97*4882a593Smuzhiyun 	{ "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 },
98*4882a593Smuzhiyun 	{ "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 },
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static const struct ksz90x1_reg_field ksz9031_ctl_grp[] = {
102*4882a593Smuzhiyun 	{ "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 }
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun static const struct ksz90x1_reg_field ksz9031_clk_grp[] = {
106*4882a593Smuzhiyun 	{ "rxc-skew-ps", 5, 0, 0xf }, { "txc-skew-ps", 5, 5, 0xf }
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
ksz90x1_of_config_group(struct phy_device * phydev,struct ksz90x1_ofcfg * ofcfg)109*4882a593Smuzhiyun static int ksz90x1_of_config_group(struct phy_device *phydev,
110*4882a593Smuzhiyun 				   struct ksz90x1_ofcfg *ofcfg)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct udevice *dev = phydev->dev;
113*4882a593Smuzhiyun 	struct phy_driver *drv = phydev->drv;
114*4882a593Smuzhiyun 	const int ps_to_regval = 60;
115*4882a593Smuzhiyun 	int val[4];
116*4882a593Smuzhiyun 	int i, changed = 0, offset, max;
117*4882a593Smuzhiyun 	u16 regval = 0;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (!drv || !drv->writeext)
120*4882a593Smuzhiyun 		return -EOPNOTSUPP;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	for (i = 0; i < ofcfg->grpsz; i++) {
123*4882a593Smuzhiyun 		val[i] = dev_read_u32_default(dev, ofcfg->grp[i].name, ~0);
124*4882a593Smuzhiyun 		offset = ofcfg->grp[i].off;
125*4882a593Smuzhiyun 		if (val[i] == -1) {
126*4882a593Smuzhiyun 			/* Default register value for KSZ9021 */
127*4882a593Smuzhiyun 			regval |= ofcfg->grp[i].dflt << offset;
128*4882a593Smuzhiyun 		} else {
129*4882a593Smuzhiyun 			changed = 1;	/* Value was changed in OF */
130*4882a593Smuzhiyun 			/* Calculate the register value and fix corner cases */
131*4882a593Smuzhiyun 			if (val[i] > ps_to_regval * 0xf) {
132*4882a593Smuzhiyun 				max = (1 << ofcfg->grp[i].size) - 1;
133*4882a593Smuzhiyun 				regval |= max << offset;
134*4882a593Smuzhiyun 			} else {
135*4882a593Smuzhiyun 				regval |= (val[i] / ps_to_regval) << offset;
136*4882a593Smuzhiyun 			}
137*4882a593Smuzhiyun 		}
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (!changed)
141*4882a593Smuzhiyun 		return 0;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return drv->writeext(phydev, 0, ofcfg->devad, ofcfg->reg, regval);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
ksz9021_of_config(struct phy_device * phydev)146*4882a593Smuzhiyun static int ksz9021_of_config(struct phy_device *phydev)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct ksz90x1_ofcfg ofcfg[] = {
149*4882a593Smuzhiyun 		{ MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0, ksz90x1_rxd_grp, 4 },
150*4882a593Smuzhiyun 		{ MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0, ksz90x1_txd_grp, 4 },
151*4882a593Smuzhiyun 		{ MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0, ksz9021_clk_grp, 4 },
152*4882a593Smuzhiyun 	};
153*4882a593Smuzhiyun 	int i, ret = 0;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
156*4882a593Smuzhiyun 		ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
157*4882a593Smuzhiyun 		if (ret)
158*4882a593Smuzhiyun 			return ret;
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
ksz9031_of_config(struct phy_device * phydev)164*4882a593Smuzhiyun static int ksz9031_of_config(struct phy_device *phydev)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct ksz90x1_ofcfg ofcfg[] = {
167*4882a593Smuzhiyun 		{ MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW, 2, ksz9031_ctl_grp, 2 },
168*4882a593Smuzhiyun 		{ MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW, 2, ksz90x1_rxd_grp, 4 },
169*4882a593Smuzhiyun 		{ MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 },
170*4882a593Smuzhiyun 		{ MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 },
171*4882a593Smuzhiyun 	};
172*4882a593Smuzhiyun 	int i, ret = 0;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ofcfg); i++) {
175*4882a593Smuzhiyun 		ret = ksz90x1_of_config_group(phydev, &(ofcfg[i]));
176*4882a593Smuzhiyun 		if (ret)
177*4882a593Smuzhiyun 			return ret;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
ksz9031_center_flp_timing(struct phy_device * phydev)183*4882a593Smuzhiyun static int ksz9031_center_flp_timing(struct phy_device *phydev)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct phy_driver *drv = phydev->drv;
186*4882a593Smuzhiyun 	int ret = 0;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (!drv || !drv->writeext)
189*4882a593Smuzhiyun 		return -EOPNOTSUPP;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_LO, 0x1A80);
192*4882a593Smuzhiyun 	if (ret)
193*4882a593Smuzhiyun 		return ret;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_HI, 0x6);
196*4882a593Smuzhiyun 	return ret;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun #else /* !CONFIG_DM_ETH */
ksz9021_of_config(struct phy_device * phydev)200*4882a593Smuzhiyun static int ksz9021_of_config(struct phy_device *phydev)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	return 0;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
ksz9031_of_config(struct phy_device * phydev)205*4882a593Smuzhiyun static int ksz9031_of_config(struct phy_device *phydev)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
ksz9031_center_flp_timing(struct phy_device * phydev)210*4882a593Smuzhiyun static int ksz9031_center_flp_timing(struct phy_device *phydev)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun #endif
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun  * KSZ9021
218*4882a593Smuzhiyun  */
ksz9021_phy_extended_write(struct phy_device * phydev,int regnum,u16 val)219*4882a593Smuzhiyun int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	/* extended registers */
222*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
223*4882a593Smuzhiyun 		  MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000);
224*4882a593Smuzhiyun 	return phy_write(phydev, MDIO_DEVAD_NONE,
225*4882a593Smuzhiyun 			 MII_KSZ9021_EXTENDED_DATAW, val);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
ksz9021_phy_extended_read(struct phy_device * phydev,int regnum)228*4882a593Smuzhiyun int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	/* extended registers */
231*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum);
232*4882a593Smuzhiyun 	return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 
ksz9021_phy_extread(struct phy_device * phydev,int addr,int devaddr,int regnum)236*4882a593Smuzhiyun static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr,
237*4882a593Smuzhiyun 			       int regnum)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	return ksz9021_phy_extended_read(phydev, regnum);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
ksz9021_phy_extwrite(struct phy_device * phydev,int addr,int devaddr,int regnum,u16 val)242*4882a593Smuzhiyun static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr,
243*4882a593Smuzhiyun 				int devaddr, int regnum, u16 val)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	return ksz9021_phy_extended_write(phydev, regnum, val);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
ksz9021_config(struct phy_device * phydev)248*4882a593Smuzhiyun static int ksz9021_config(struct phy_device *phydev)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	unsigned ctrl1000 = 0;
251*4882a593Smuzhiyun 	const unsigned master = CTRL1000_PREFER_MASTER |
252*4882a593Smuzhiyun 	CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG;
253*4882a593Smuzhiyun 	unsigned features = phydev->drv->features;
254*4882a593Smuzhiyun 	int ret;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	ret = ksz9021_of_config(phydev);
257*4882a593Smuzhiyun 	if (ret)
258*4882a593Smuzhiyun 		return ret;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (env_get("disable_giga"))
261*4882a593Smuzhiyun 		features &= ~(SUPPORTED_1000baseT_Half |
262*4882a593Smuzhiyun 		SUPPORTED_1000baseT_Full);
263*4882a593Smuzhiyun 	/* force master mode for 1000BaseT due to chip errata */
264*4882a593Smuzhiyun 	if (features & SUPPORTED_1000baseT_Half)
265*4882a593Smuzhiyun 		ctrl1000 |= ADVERTISE_1000HALF | master;
266*4882a593Smuzhiyun 	if (features & SUPPORTED_1000baseT_Full)
267*4882a593Smuzhiyun 		ctrl1000 |= ADVERTISE_1000FULL | master;
268*4882a593Smuzhiyun 	phydev->advertising = features;
269*4882a593Smuzhiyun 	phydev->supported = features;
270*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000);
271*4882a593Smuzhiyun 	genphy_config_aneg(phydev);
272*4882a593Smuzhiyun 	genphy_restart_aneg(phydev);
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun static struct phy_driver ksz9021_driver = {
277*4882a593Smuzhiyun 	.name = "Micrel ksz9021",
278*4882a593Smuzhiyun 	.uid  = 0x221610,
279*4882a593Smuzhiyun 	.mask = 0xfffff0,
280*4882a593Smuzhiyun 	.features = PHY_GBIT_FEATURES,
281*4882a593Smuzhiyun 	.config = &ksz9021_config,
282*4882a593Smuzhiyun 	.startup = &ksz90xx_startup,
283*4882a593Smuzhiyun 	.shutdown = &genphy_shutdown,
284*4882a593Smuzhiyun 	.writeext = &ksz9021_phy_extwrite,
285*4882a593Smuzhiyun 	.readext = &ksz9021_phy_extread,
286*4882a593Smuzhiyun };
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun /*
289*4882a593Smuzhiyun  * KSZ9031
290*4882a593Smuzhiyun  */
ksz9031_phy_extended_write(struct phy_device * phydev,int devaddr,int regnum,u16 mode,u16 val)291*4882a593Smuzhiyun int ksz9031_phy_extended_write(struct phy_device *phydev,
292*4882a593Smuzhiyun 			       int devaddr, int regnum, u16 mode, u16 val)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	/*select register addr for mmd*/
295*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
296*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
297*4882a593Smuzhiyun 	/*select register for mmd*/
298*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
299*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_REG_DATA, regnum);
300*4882a593Smuzhiyun 	/*setup mode*/
301*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
302*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
303*4882a593Smuzhiyun 	/*write the value*/
304*4882a593Smuzhiyun 	return	phy_write(phydev, MDIO_DEVAD_NONE,
305*4882a593Smuzhiyun 			  MII_KSZ9031_MMD_REG_DATA, val);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
ksz9031_phy_extended_read(struct phy_device * phydev,int devaddr,int regnum,u16 mode)308*4882a593Smuzhiyun int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
309*4882a593Smuzhiyun 			      int regnum, u16 mode)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
312*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
313*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
314*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_REG_DATA, regnum);
315*4882a593Smuzhiyun 	phy_write(phydev, MDIO_DEVAD_NONE,
316*4882a593Smuzhiyun 		  MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
317*4882a593Smuzhiyun 	return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
ksz9031_phy_extread(struct phy_device * phydev,int addr,int devaddr,int regnum)320*4882a593Smuzhiyun static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr,
321*4882a593Smuzhiyun 			       int regnum)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	return ksz9031_phy_extended_read(phydev, devaddr, regnum,
324*4882a593Smuzhiyun 					 MII_KSZ9031_MOD_DATA_NO_POST_INC);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
ksz9031_phy_extwrite(struct phy_device * phydev,int addr,int devaddr,int regnum,u16 val)327*4882a593Smuzhiyun static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr,
328*4882a593Smuzhiyun 				int devaddr, int regnum, u16 val)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	return ksz9031_phy_extended_write(phydev, devaddr, regnum,
331*4882a593Smuzhiyun 					  MII_KSZ9031_MOD_DATA_POST_INC_RW, val);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
ksz9031_config(struct phy_device * phydev)334*4882a593Smuzhiyun static int ksz9031_config(struct phy_device *phydev)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	int ret;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	ret = ksz9031_of_config(phydev);
339*4882a593Smuzhiyun 	if (ret)
340*4882a593Smuzhiyun 		return ret;
341*4882a593Smuzhiyun 	ret = ksz9031_center_flp_timing(phydev);
342*4882a593Smuzhiyun 	if (ret)
343*4882a593Smuzhiyun 		return ret;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	/* add an option to disable the gigabit feature of this PHY */
346*4882a593Smuzhiyun 	if (env_get("disable_giga")) {
347*4882a593Smuzhiyun 		unsigned features;
348*4882a593Smuzhiyun 		unsigned bmcr;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 		/* disable speed 1000 in features supported by the PHY */
351*4882a593Smuzhiyun 		features = phydev->drv->features;
352*4882a593Smuzhiyun 		features &= ~(SUPPORTED_1000baseT_Half |
353*4882a593Smuzhiyun 				SUPPORTED_1000baseT_Full);
354*4882a593Smuzhiyun 		phydev->advertising = phydev->supported = features;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		/* disable speed 1000 in Basic Control Register */
357*4882a593Smuzhiyun 		bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
358*4882a593Smuzhiyun 		bmcr &= ~(1 << 6);
359*4882a593Smuzhiyun 		phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		/* disable speed 1000 in 1000Base-T Control Register */
362*4882a593Smuzhiyun 		phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, 0);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		/* start autoneg */
365*4882a593Smuzhiyun 		genphy_config_aneg(phydev);
366*4882a593Smuzhiyun 		genphy_restart_aneg(phydev);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 		return 0;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return genphy_config(phydev);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun static struct phy_driver ksz9031_driver = {
375*4882a593Smuzhiyun 	.name = "Micrel ksz9031",
376*4882a593Smuzhiyun 	.uid  = 0x221620,
377*4882a593Smuzhiyun 	.mask = 0xfffff0,
378*4882a593Smuzhiyun 	.features = PHY_GBIT_FEATURES,
379*4882a593Smuzhiyun 	.config   = &ksz9031_config,
380*4882a593Smuzhiyun 	.startup  = &ksz90xx_startup,
381*4882a593Smuzhiyun 	.shutdown = &genphy_shutdown,
382*4882a593Smuzhiyun 	.writeext = &ksz9031_phy_extwrite,
383*4882a593Smuzhiyun 	.readext = &ksz9031_phy_extread,
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun 
phy_micrel_ksz90x1_init(void)386*4882a593Smuzhiyun int phy_micrel_ksz90x1_init(void)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	phy_register(&ksz9021_driver);
389*4882a593Smuzhiyun 	phy_register(&ksz9031_driver);
390*4882a593Smuzhiyun 	return 0;
391*4882a593Smuzhiyun }
392