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