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 */
10*4882a593Smuzhiyun #include <config.h>
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <dm.h>
13*4882a593Smuzhiyun #include <errno.h>
14*4882a593Smuzhiyun #include <fdtdec.h>
15*4882a593Smuzhiyun #include <micrel.h>
16*4882a593Smuzhiyun #include <phy.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun static struct phy_driver KSZ804_driver = {
21*4882a593Smuzhiyun .name = "Micrel KSZ804",
22*4882a593Smuzhiyun .uid = 0x221510,
23*4882a593Smuzhiyun .mask = 0xfffff0,
24*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
25*4882a593Smuzhiyun .config = &genphy_config,
26*4882a593Smuzhiyun .startup = &genphy_startup,
27*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define MII_KSZPHY_OMSO 0x16
31*4882a593Smuzhiyun #define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
32*4882a593Smuzhiyun
ksz_genconfig_bcastoff(struct phy_device * phydev)33*4882a593Smuzhiyun static int ksz_genconfig_bcastoff(struct phy_device *phydev)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun int ret;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
38*4882a593Smuzhiyun if (ret < 0)
39*4882a593Smuzhiyun return ret;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
42*4882a593Smuzhiyun ret | KSZPHY_OMSO_B_CAST_OFF);
43*4882a593Smuzhiyun if (ret < 0)
44*4882a593Smuzhiyun return ret;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return genphy_config(phydev);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static struct phy_driver KSZ8031_driver = {
50*4882a593Smuzhiyun .name = "Micrel KSZ8021/KSZ8031",
51*4882a593Smuzhiyun .uid = 0x221550,
52*4882a593Smuzhiyun .mask = 0xfffff0,
53*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
54*4882a593Smuzhiyun .config = &ksz_genconfig_bcastoff,
55*4882a593Smuzhiyun .startup = &genphy_startup,
56*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /**
60*4882a593Smuzhiyun * KSZ8051
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun #define MII_KSZ8051_PHY_OMSO 0x16
63*4882a593Smuzhiyun #define MII_KSZ8051_PHY_OMSO_NAND_TREE_ON (1 << 5)
64*4882a593Smuzhiyun
ksz8051_config(struct phy_device * phydev)65*4882a593Smuzhiyun static int ksz8051_config(struct phy_device *phydev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun unsigned val;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Disable NAND-tree */
70*4882a593Smuzhiyun val = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO);
71*4882a593Smuzhiyun val &= ~MII_KSZ8051_PHY_OMSO_NAND_TREE_ON;
72*4882a593Smuzhiyun phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO, val);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return genphy_config(phydev);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun static struct phy_driver KSZ8051_driver = {
78*4882a593Smuzhiyun .name = "Micrel KSZ8051",
79*4882a593Smuzhiyun .uid = 0x221550,
80*4882a593Smuzhiyun .mask = 0xfffff0,
81*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
82*4882a593Smuzhiyun .config = &ksz8051_config,
83*4882a593Smuzhiyun .startup = &genphy_startup,
84*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun static struct phy_driver KSZ8081_driver = {
88*4882a593Smuzhiyun .name = "Micrel KSZ8081",
89*4882a593Smuzhiyun .uid = 0x221560,
90*4882a593Smuzhiyun .mask = 0xfffff0,
91*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
92*4882a593Smuzhiyun .config = &ksz_genconfig_bcastoff,
93*4882a593Smuzhiyun .startup = &genphy_startup,
94*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /**
98*4882a593Smuzhiyun * KSZ8895
99*4882a593Smuzhiyun */
100*4882a593Smuzhiyun
smireg_to_phy(unsigned short reg)101*4882a593Smuzhiyun static unsigned short smireg_to_phy(unsigned short reg)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun return ((reg & 0xc0) >> 3) + 0x06 + ((reg & 0x20) >> 5);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
smireg_to_reg(unsigned short reg)106*4882a593Smuzhiyun static unsigned short smireg_to_reg(unsigned short reg)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun return reg & 0x1F;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
ksz8895_write_smireg(struct phy_device * phydev,int smireg,int val)111*4882a593Smuzhiyun static void ksz8895_write_smireg(struct phy_device *phydev, int smireg, int val)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun phydev->bus->write(phydev->bus, smireg_to_phy(smireg), MDIO_DEVAD_NONE,
114*4882a593Smuzhiyun smireg_to_reg(smireg), val);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun #if 0
118*4882a593Smuzhiyun static int ksz8895_read_smireg(struct phy_device *phydev, int smireg)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun return phydev->bus->read(phydev->bus, smireg_to_phy(smireg),
121*4882a593Smuzhiyun MDIO_DEVAD_NONE, smireg_to_reg(smireg));
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun #endif
124*4882a593Smuzhiyun
ksz8895_config(struct phy_device * phydev)125*4882a593Smuzhiyun int ksz8895_config(struct phy_device *phydev)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun /* we are connected directly to the switch without
128*4882a593Smuzhiyun * dedicated PHY. SCONF1 == 001 */
129*4882a593Smuzhiyun phydev->link = 1;
130*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
131*4882a593Smuzhiyun phydev->speed = SPEED_100;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Force the switch to start */
134*4882a593Smuzhiyun ksz8895_write_smireg(phydev, 1, 1);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
ksz8895_startup(struct phy_device * phydev)139*4882a593Smuzhiyun static int ksz8895_startup(struct phy_device *phydev)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun static struct phy_driver ksz8895_driver = {
145*4882a593Smuzhiyun .name = "Micrel KSZ8895/KSZ8864",
146*4882a593Smuzhiyun .uid = 0x221450,
147*4882a593Smuzhiyun .mask = 0xffffe1,
148*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
149*4882a593Smuzhiyun .config = &ksz8895_config,
150*4882a593Smuzhiyun .startup = &ksz8895_startup,
151*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* Micrel used the exact same part number for the KSZ9021. */
155*4882a593Smuzhiyun static struct phy_driver KS8721_driver = {
156*4882a593Smuzhiyun .name = "Micrel KS8721BL",
157*4882a593Smuzhiyun .uid = 0x221610,
158*4882a593Smuzhiyun .mask = 0xfffff0,
159*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
160*4882a593Smuzhiyun .config = &genphy_config,
161*4882a593Smuzhiyun .startup = &genphy_startup,
162*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun
ksz886x_config(struct phy_device * phydev)165*4882a593Smuzhiyun int ksz886x_config(struct phy_device *phydev)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun /* we are connected directly to the switch without
168*4882a593Smuzhiyun * dedicated PHY. */
169*4882a593Smuzhiyun phydev->link = 1;
170*4882a593Smuzhiyun phydev->duplex = DUPLEX_FULL;
171*4882a593Smuzhiyun phydev->speed = SPEED_100;
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
ksz886x_startup(struct phy_device * phydev)175*4882a593Smuzhiyun static int ksz886x_startup(struct phy_device *phydev)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun return 0;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun static struct phy_driver ksz886x_driver = {
181*4882a593Smuzhiyun .name = "Micrel KSZ886x Switch",
182*4882a593Smuzhiyun .uid = 0x00221430,
183*4882a593Smuzhiyun .mask = 0xfffff0,
184*4882a593Smuzhiyun .features = PHY_BASIC_FEATURES,
185*4882a593Smuzhiyun .config = &ksz886x_config,
186*4882a593Smuzhiyun .startup = &ksz886x_startup,
187*4882a593Smuzhiyun .shutdown = &genphy_shutdown,
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun
phy_micrel_ksz8xxx_init(void)190*4882a593Smuzhiyun int phy_micrel_ksz8xxx_init(void)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun phy_register(&KSZ804_driver);
193*4882a593Smuzhiyun phy_register(&KSZ8031_driver);
194*4882a593Smuzhiyun phy_register(&KSZ8051_driver);
195*4882a593Smuzhiyun phy_register(&KSZ8081_driver);
196*4882a593Smuzhiyun phy_register(&KS8721_driver);
197*4882a593Smuzhiyun phy_register(&ksz8895_driver);
198*4882a593Smuzhiyun phy_register(&ksz886x_driver);
199*4882a593Smuzhiyun return 0;
200*4882a593Smuzhiyun }
201