Skip to content

Commit aac9400

Browse files
luizlucadavem330
authored andcommitted
net: dsa: realtek: add new mdio interface for drivers
This driver is a mdio_driver instead of a platform driver (like realtek-smi). ds_ops was duplicated for smi and mdio usage as mdio interfaces uses phy_{read,write} in ds_ops and the presence of phy_read is incompatible with external slave_mii_bus allocation. Signed-off-by: Luiz Angelo Daros de Luca <[email protected]> Tested-by: Arınç ÜNAL <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 765c39a commit aac9400

File tree

7 files changed

+317
-8
lines changed

7 files changed

+317
-8
lines changed

drivers/net/dsa/realtek/Kconfig

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ menuconfig NET_DSA_REALTEK
99
help
1010
Select to enable support for Realtek Ethernet switch chips.
1111

12+
config NET_DSA_REALTEK_MDIO
13+
tristate "Realtek MDIO connected switch driver"
14+
depends on NET_DSA_REALTEK
15+
default y
16+
help
17+
Select to enable support for registering switches configured
18+
through MDIO.
19+
1220
config NET_DSA_REALTEK_SMI
1321
tristate "Realtek SMI connected switch driver"
1422
depends on NET_DSA_REALTEK
@@ -21,7 +29,7 @@ config NET_DSA_REALTEK_RTL8365MB
2129
tristate "Realtek RTL8365MB switch subdriver"
2230
default y
2331
depends on NET_DSA_REALTEK
24-
depends on NET_DSA_REALTEK_SMI
32+
depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO
2533
select NET_DSA_TAG_RTL8_4
2634
help
2735
Select to enable support for Realtek RTL8365MB
@@ -30,7 +38,7 @@ config NET_DSA_REALTEK_RTL8366RB
3038
tristate "Realtek RTL8366RB switch subdriver"
3139
default y
3240
depends on NET_DSA_REALTEK
33-
depends on NET_DSA_REALTEK_SMI
41+
depends on NET_DSA_REALTEK_SMI || NET_DSA_REALTEK_MDIO
3442
select NET_DSA_TAG_RTL4_A
3543
help
3644
Select to enable support for Realtek RTL8366RB

drivers/net/dsa/realtek/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0
2+
obj-$(CONFIG_NET_DSA_REALTEK_MDIO) += realtek-mdio.o
23
obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
34
obj-$(CONFIG_NET_DSA_REALTEK_RTL8366RB) += rtl8366.o
45
rtl8366-objs := rtl8366-core.o rtl8366rb.o
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/* Realtek MDIO interface driver
3+
*
4+
* ASICs we intend to support with this driver:
5+
*
6+
* RTL8366 - The original version, apparently
7+
* RTL8369 - Similar enough to have the same datsheet as RTL8366
8+
* RTL8366RB - Probably reads out "RTL8366 revision B", has a quite
9+
* different register layout from the other two
10+
* RTL8366S - Is this "RTL8366 super"?
11+
* RTL8367 - Has an OpenWRT driver as well
12+
* RTL8368S - Seems to be an alternative name for RTL8366RB
13+
* RTL8370 - Also uses SMI
14+
*
15+
* Copyright (C) 2017 Linus Walleij <[email protected]>
16+
* Copyright (C) 2010 Antti Seppälä <[email protected]>
17+
* Copyright (C) 2010 Roman Yeryomin <[email protected]>
18+
* Copyright (C) 2011 Colin Leitner <[email protected]>
19+
* Copyright (C) 2009-2010 Gabor Juhos <[email protected]>
20+
*/
21+
22+
#include <linux/module.h>
23+
#include <linux/of_device.h>
24+
#include <linux/regmap.h>
25+
26+
#include "realtek.h"
27+
28+
/* Read/write via mdiobus */
29+
#define REALTEK_MDIO_CTRL0_REG 31
30+
#define REALTEK_MDIO_START_REG 29
31+
#define REALTEK_MDIO_CTRL1_REG 21
32+
#define REALTEK_MDIO_ADDRESS_REG 23
33+
#define REALTEK_MDIO_DATA_WRITE_REG 24
34+
#define REALTEK_MDIO_DATA_READ_REG 25
35+
36+
#define REALTEK_MDIO_START_OP 0xFFFF
37+
#define REALTEK_MDIO_ADDR_OP 0x000E
38+
#define REALTEK_MDIO_READ_OP 0x0001
39+
#define REALTEK_MDIO_WRITE_OP 0x0003
40+
41+
static int realtek_mdio_write(void *ctx, u32 reg, u32 val)
42+
{
43+
struct realtek_priv *priv = ctx;
44+
struct mii_bus *bus = priv->bus;
45+
int ret;
46+
47+
mutex_lock(&bus->mdio_lock);
48+
49+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP);
50+
if (ret)
51+
goto out_unlock;
52+
53+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg);
54+
if (ret)
55+
goto out_unlock;
56+
57+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_DATA_WRITE_REG, val);
58+
if (ret)
59+
goto out_unlock;
60+
61+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_WRITE_OP);
62+
63+
out_unlock:
64+
mutex_unlock(&bus->mdio_lock);
65+
66+
return ret;
67+
}
68+
69+
static int realtek_mdio_read(void *ctx, u32 reg, u32 *val)
70+
{
71+
struct realtek_priv *priv = ctx;
72+
struct mii_bus *bus = priv->bus;
73+
int ret;
74+
75+
mutex_lock(&bus->mdio_lock);
76+
77+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP);
78+
if (ret)
79+
goto out_unlock;
80+
81+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg);
82+
if (ret)
83+
goto out_unlock;
84+
85+
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_READ_OP);
86+
if (ret)
87+
goto out_unlock;
88+
89+
ret = bus->read(bus, priv->mdio_addr, REALTEK_MDIO_DATA_READ_REG);
90+
if (ret >= 0) {
91+
*val = ret;
92+
ret = 0;
93+
}
94+
95+
out_unlock:
96+
mutex_unlock(&bus->mdio_lock);
97+
98+
return ret;
99+
}
100+
101+
static const struct regmap_config realtek_mdio_regmap_config = {
102+
.reg_bits = 10, /* A4..A0 R4..R0 */
103+
.val_bits = 16,
104+
.reg_stride = 1,
105+
/* PHY regs are at 0x8000 */
106+
.max_register = 0xffff,
107+
.reg_format_endian = REGMAP_ENDIAN_BIG,
108+
.reg_read = realtek_mdio_read,
109+
.reg_write = realtek_mdio_write,
110+
.cache_type = REGCACHE_NONE,
111+
};
112+
113+
static int realtek_mdio_probe(struct mdio_device *mdiodev)
114+
{
115+
struct realtek_priv *priv;
116+
struct device *dev = &mdiodev->dev;
117+
const struct realtek_variant *var;
118+
int ret;
119+
struct device_node *np;
120+
121+
var = of_device_get_match_data(dev);
122+
if (!var)
123+
return -EINVAL;
124+
125+
priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
126+
if (!priv)
127+
return -ENOMEM;
128+
129+
priv->map = devm_regmap_init(dev, NULL, priv, &realtek_mdio_regmap_config);
130+
if (IS_ERR(priv->map)) {
131+
ret = PTR_ERR(priv->map);
132+
dev_err(dev, "regmap init failed: %d\n", ret);
133+
return ret;
134+
}
135+
136+
priv->mdio_addr = mdiodev->addr;
137+
priv->bus = mdiodev->bus;
138+
priv->dev = &mdiodev->dev;
139+
priv->chip_data = (void *)priv + sizeof(*priv);
140+
141+
priv->clk_delay = var->clk_delay;
142+
priv->cmd_read = var->cmd_read;
143+
priv->cmd_write = var->cmd_write;
144+
priv->ops = var->ops;
145+
146+
priv->write_reg_noack = realtek_mdio_write;
147+
148+
np = dev->of_node;
149+
150+
dev_set_drvdata(dev, priv);
151+
152+
/* TODO: if power is software controlled, set up any regulators here */
153+
priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
154+
155+
ret = priv->ops->detect(priv);
156+
if (ret) {
157+
dev_err(dev, "unable to detect switch\n");
158+
return ret;
159+
}
160+
161+
priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
162+
if (!priv->ds)
163+
return -ENOMEM;
164+
165+
priv->ds->dev = dev;
166+
priv->ds->num_ports = priv->num_ports;
167+
priv->ds->priv = priv;
168+
priv->ds->ops = var->ds_ops_mdio;
169+
170+
ret = dsa_register_switch(priv->ds);
171+
if (ret) {
172+
dev_err(priv->dev, "unable to register switch ret = %d\n", ret);
173+
return ret;
174+
}
175+
176+
return 0;
177+
}
178+
179+
static void realtek_mdio_remove(struct mdio_device *mdiodev)
180+
{
181+
struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
182+
183+
if (!priv)
184+
return;
185+
186+
dsa_unregister_switch(priv->ds);
187+
188+
dev_set_drvdata(&mdiodev->dev, NULL);
189+
}
190+
191+
static void realtek_mdio_shutdown(struct mdio_device *mdiodev)
192+
{
193+
struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
194+
195+
if (!priv)
196+
return;
197+
198+
dsa_switch_shutdown(priv->ds);
199+
200+
dev_set_drvdata(&mdiodev->dev, NULL);
201+
}
202+
203+
static const struct of_device_id realtek_mdio_of_match[] = {
204+
#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB)
205+
{ .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, },
206+
#endif
207+
#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB)
208+
{ .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, },
209+
#endif
210+
{ /* sentinel */ },
211+
};
212+
MODULE_DEVICE_TABLE(of, realtek_mdio_of_match);
213+
214+
static struct mdio_driver realtek_mdio_driver = {
215+
.mdiodrv.driver = {
216+
.name = "realtek-mdio",
217+
.of_match_table = of_match_ptr(realtek_mdio_of_match),
218+
},
219+
.probe = realtek_mdio_probe,
220+
.remove = realtek_mdio_remove,
221+
.shutdown = realtek_mdio_shutdown,
222+
};
223+
224+
mdio_module_driver(realtek_mdio_driver);
225+
226+
MODULE_AUTHOR("Luiz Angelo Daros de Luca <[email protected]>");
227+
MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface");
228+
MODULE_LICENSE("GPL");

drivers/net/dsa/realtek/realtek-smi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ static int realtek_smi_probe(struct platform_device *pdev)
455455
priv->ds->num_ports = priv->num_ports;
456456
priv->ds->priv = priv;
457457

458-
priv->ds->ops = var->ds_ops;
458+
priv->ds->ops = var->ds_ops_smi;
459459
ret = dsa_register_switch(priv->ds);
460460
if (ret) {
461461
dev_err_probe(dev, ret, "unable to register switch\n");

drivers/net/dsa/realtek/realtek.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ struct realtek_priv {
5050
struct gpio_desc *mdio;
5151
struct regmap *map;
5252
struct mii_bus *slave_mii_bus;
53+
struct mii_bus *bus;
54+
int mdio_addr;
5355

5456
unsigned int clk_delay;
5557
u8 cmd_read;
@@ -109,7 +111,8 @@ struct realtek_ops {
109111
};
110112

111113
struct realtek_variant {
112-
const struct dsa_switch_ops *ds_ops;
114+
const struct dsa_switch_ops *ds_ops_smi;
115+
const struct dsa_switch_ops *ds_ops_mdio;
113116
const struct realtek_ops *ops;
114117
unsigned int clk_delay;
115118
u8 cmd_read;

drivers/net/dsa/realtek/rtl8365mb.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,17 @@ static int rtl8365mb_phy_write(struct realtek_priv *priv, int phy, int regnum,
730730
return 0;
731731
}
732732

733+
static int rtl8365mb_dsa_phy_read(struct dsa_switch *ds, int phy, int regnum)
734+
{
735+
return rtl8365mb_phy_read(ds->priv, phy, regnum);
736+
}
737+
738+
static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum,
739+
u16 val)
740+
{
741+
return rtl8365mb_phy_write(ds->priv, phy, regnum, val);
742+
}
743+
733744
static enum dsa_tag_protocol
734745
rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port,
735746
enum dsa_tag_protocol mp)
@@ -1953,14 +1964,34 @@ static int rtl8365mb_detect(struct realtek_priv *priv)
19531964
return 0;
19541965
}
19551966

1956-
static const struct dsa_switch_ops rtl8365mb_switch_ops = {
1967+
static const struct dsa_switch_ops rtl8365mb_switch_ops_smi = {
1968+
.get_tag_protocol = rtl8365mb_get_tag_protocol,
1969+
.setup = rtl8365mb_setup,
1970+
.teardown = rtl8365mb_teardown,
1971+
.phylink_validate = rtl8365mb_phylink_validate,
1972+
.phylink_mac_config = rtl8365mb_phylink_mac_config,
1973+
.phylink_mac_link_down = rtl8365mb_phylink_mac_link_down,
1974+
.phylink_mac_link_up = rtl8365mb_phylink_mac_link_up,
1975+
.port_stp_state_set = rtl8365mb_port_stp_state_set,
1976+
.get_strings = rtl8365mb_get_strings,
1977+
.get_ethtool_stats = rtl8365mb_get_ethtool_stats,
1978+
.get_sset_count = rtl8365mb_get_sset_count,
1979+
.get_eth_phy_stats = rtl8365mb_get_phy_stats,
1980+
.get_eth_mac_stats = rtl8365mb_get_mac_stats,
1981+
.get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats,
1982+
.get_stats64 = rtl8365mb_get_stats64,
1983+
};
1984+
1985+
static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = {
19571986
.get_tag_protocol = rtl8365mb_get_tag_protocol,
19581987
.setup = rtl8365mb_setup,
19591988
.teardown = rtl8365mb_teardown,
19601989
.phylink_validate = rtl8365mb_phylink_validate,
19611990
.phylink_mac_config = rtl8365mb_phylink_mac_config,
19621991
.phylink_mac_link_down = rtl8365mb_phylink_mac_link_down,
19631992
.phylink_mac_link_up = rtl8365mb_phylink_mac_link_up,
1993+
.phy_read = rtl8365mb_dsa_phy_read,
1994+
.phy_write = rtl8365mb_dsa_phy_write,
19641995
.port_stp_state_set = rtl8365mb_port_stp_state_set,
19651996
.get_strings = rtl8365mb_get_strings,
19661997
.get_ethtool_stats = rtl8365mb_get_ethtool_stats,
@@ -1978,7 +2009,8 @@ static const struct realtek_ops rtl8365mb_ops = {
19782009
};
19792010

19802011
const struct realtek_variant rtl8365mb_variant = {
1981-
.ds_ops = &rtl8365mb_switch_ops,
2012+
.ds_ops_smi = &rtl8365mb_switch_ops_smi,
2013+
.ds_ops_mdio = &rtl8365mb_switch_ops_mdio,
19822014
.ops = &rtl8365mb_ops,
19832015
.clk_delay = 10,
19842016
.cmd_read = 0xb9,

0 commit comments

Comments
 (0)