summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/patches-6.18/723-net-mdio-Add-Realtek-Otto-auxiliary-controller.patch
blob: 59157cc52dcb42a0efde20a45bbedca68c5d961e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
From ffb7da9aa25765b2115e7ff3ee4f6dafa60f5421 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Fri, 27 Dec 2024 14:55:31 +0100
Subject: [PATCH] net: mdio: Add Realtek Otto auxiliary controller

SoCs in Realtek's Otto platform such as the RTL8380, RTL8391, and
RTL9302 have a simple auxiliary MDIO controller that is commonly used to
manage RTL8231 GPIO expanders on switch devices.

Add a new MDIO controller driver supporting the RTL838x (maple), RTL839x
(cypress), and RTL930x (longan) SoCs.

Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
 drivers/net/mdio/Kconfig                 |  10 ++
 drivers/net/mdio/Makefile                |   1 +
 drivers/net/mdio/mdio-realtek-otto-aux.c | 175 +++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 drivers/net/mdio/mdio-realtek-otto-aux.c

--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -191,6 +191,16 @@ config MDIO_REGMAP
 	  regmap. Users willing to use this driver must explicitly select
 	  REGMAP.
 
+config MDIO_REALTEK_OTTO_AUX
+	tristate "Realtek Otto auxiliary MDIO interface support"
+	default MACH_REALTEK_RTL
+	depends on MACH_REALTEK_RTL
+	depends on MFD_SYSCON
+	select MDIO_DEVRES
+	help
+	  This driver supports the auxilairy MDIO bus on RTL838x SoCs. This bus
+	  is typically used to attach RTL8231 GPIO extenders.
+
 config MDIO_THUNDER
 	tristate "ThunderX SOCs MDIO buses"
 	depends on 64BIT
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_MVUSB)		+= mdio-mvusb.
 obj-$(CONFIG_MDIO_OCTEON)		+= mdio-octeon.o
 obj-$(CONFIG_MDIO_REALTEK_RTL9300)	+= mdio-realtek-rtl9300.o
 obj-$(CONFIG_MDIO_REGMAP)		+= mdio-regmap.o
+obj-$(CONFIG_MDIO_REALTEK_OTTO_AUX)	+= mdio-realtek-otto-aux.o
 obj-$(CONFIG_MDIO_SMBUS)		+= mdio-smbus.o
 obj-$(CONFIG_MDIO_SUN4I)		+= mdio-sun4i.o
 obj-$(CONFIG_MDIO_THUNDER)		+= mdio-thunder.o
--- /dev/null
+++ b/drivers/net/mdio/mdio-realtek-otto-aux.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define RTL8380_EXT_GPIO_INDIRECT_ACCESS	0xA09C
+#define RTL8390_EXT_GPIO_INDIRECT_ACCESS	0x0224
+#define RTL9300_EXT_GPIO_INDIRECT_ACCESS	0xC620
+#define RTL9310_EXT_GPIO_INDIRECT_ACCESS	0x07F4
+
+#define RTL83XX_AUX_MDIO_DATA_OFFSET		16
+#define RTL83XX_AUX_MDIO_RCMD_FAIL		0
+
+#define RTL93XX_AUX_MDIO_DATA_OFFSET		12
+#define RTL93XX_AUX_MDIO_RCMD_FAIL		BIT(28)
+
+#define REALTEK_AUX_MDIO_REG			GENMASK(11, 7)
+#define REALTEK_AUX_MDIO_PHY_ADDR		GENMASK(6, 2)
+#define REALTEK_AUX_MDIO_WRITE			BIT(1)
+#define REALTEK_AUX_MDIO_READ			0
+#define REALTEK_AUX_MDIO_EXEC			BIT(0)
+
+struct realtek_aux_mdio_info {
+	unsigned int cmd_reg;
+	unsigned int data_offset;
+	unsigned int rcmd_fail_mask;
+	unsigned int timeout_us;
+};
+
+static const struct realtek_aux_mdio_info info_rtl838x = {
+	.cmd_reg = RTL8380_EXT_GPIO_INDIRECT_ACCESS,
+	.data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
+	.rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
+	.timeout_us = 1700,
+};
+
+static const struct realtek_aux_mdio_info info_rtl839x = {
+	.cmd_reg = RTL8390_EXT_GPIO_INDIRECT_ACCESS,
+	.data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
+	.rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
+	.timeout_us = 4120,
+};
+
+static const struct realtek_aux_mdio_info info_rtl930x = {
+	.cmd_reg = RTL9300_EXT_GPIO_INDIRECT_ACCESS,
+	.data_offset = RTL93XX_AUX_MDIO_DATA_OFFSET,
+	.rcmd_fail_mask = RTL93XX_AUX_MDIO_RCMD_FAIL,
+	.timeout_us = 19000,
+};
+
+static const struct realtek_aux_mdio_info info_rtl931x = {
+	.cmd_reg = RTL9310_EXT_GPIO_INDIRECT_ACCESS,
+	.data_offset = RTL93XX_AUX_MDIO_DATA_OFFSET,
+	.rcmd_fail_mask = RTL93XX_AUX_MDIO_RCMD_FAIL,
+	.timeout_us = 19000,
+};
+
+struct realtek_aux_mdio_ctrl {
+	struct device *dev;
+	struct regmap *map;
+	const struct realtek_aux_mdio_info *info;
+};
+
+#define mii_bus_to_ctrl(bus)	((struct realtek_aux_mdio_ctrl *) bus->priv)
+
+static int realtek_aux_mdio_cmd(struct realtek_aux_mdio_ctrl *ctrl, int addr, int regnum,
+		u32 rw_bit, u16 *data)
+{
+	unsigned int cmd;
+	int err;
+
+	cmd = rw_bit | REALTEK_AUX_MDIO_EXEC;
+	cmd |= FIELD_PREP(REALTEK_AUX_MDIO_PHY_ADDR, addr);
+	cmd |= FIELD_PREP(REALTEK_AUX_MDIO_REG, regnum);
+
+	if (rw_bit == REALTEK_AUX_MDIO_WRITE)
+		cmd |= *data << ctrl->info->data_offset;
+
+	err = regmap_write(ctrl->map, ctrl->info->cmd_reg, cmd);
+	if (err)
+		return err;
+
+	err = regmap_read_poll_timeout_atomic(ctrl->map, ctrl->info->cmd_reg, cmd,
+			!(cmd & REALTEK_AUX_MDIO_EXEC), 3, ctrl->info->timeout_us);
+	if (err)
+		return err;
+
+	if (rw_bit == REALTEK_AUX_MDIO_READ) {
+		if (cmd & ctrl->info->rcmd_fail_mask)
+			return -EIO;
+
+		*data = (cmd >> ctrl->info->data_offset) & GENMASK(15, 0);
+	}
+
+	return 0;
+}
+
+static int realtek_aux_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+	struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
+	u16 data;
+	int err;
+
+	err = realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_READ, &data);
+
+	if (err)
+		return err;
+	else
+		return data;
+}
+
+static int realtek_aux_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+	struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
+
+	return realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_WRITE, &val);
+}
+
+static int realtek_aux_mdio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct realtek_aux_mdio_ctrl *ctrl;
+	struct mii_bus *bus;
+
+	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctrl));
+	if (!bus)
+		return -ENOMEM;
+
+	ctrl = bus->priv;
+	ctrl->dev = &pdev->dev;
+	ctrl->info = (const struct realtek_aux_mdio_info *) device_get_match_data(ctrl->dev);
+	ctrl->map = syscon_node_to_regmap(np->parent);
+	if (IS_ERR(ctrl->map))
+		return PTR_ERR(ctrl->map);
+
+	bus->name = "Realtek auxiliary MDIO bus";
+	snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-aux-mdio") ;
+	bus->parent = ctrl->dev;
+	bus->read = realtek_aux_mdio_read;
+	bus->write = realtek_aux_mdio_write;
+	/* Don't have interrupts */
+	for (unsigned int i = 0; i < PHY_MAX_ADDR; i++)
+		bus->irq[i] = PHY_POLL;
+
+	return devm_of_mdiobus_register(ctrl->dev, bus, np);
+}
+
+static const struct of_device_id realtek_aux_mdio_of_match[] = {
+	{
+		.compatible = "realtek,rtl8380-aux-mdio",
+		.data = &info_rtl838x,
+	},
+	{
+		.compatible = "realtek,rtl8390-aux-mdio",
+		.data = &info_rtl839x,
+	},
+	{
+		.compatible = "realtek,rtl9300-aux-mdio",
+		.data = &info_rtl930x,
+	},
+	{
+		.compatible = "realtek,rtl9310-aux-mdio",
+		.data = &info_rtl931x,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, realtek_aux_mdio_of_match);
+
+static struct platform_driver realtek_aux_mdio_driver = {
+	.driver = {
+		.name = "realtek-otto-aux-mdio",
+		.of_match_table = realtek_aux_mdio_of_match
+	},
+	.probe = realtek_aux_mdio_probe,
+};
+module_platform_driver(realtek_aux_mdio_driver);
+
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Realtek otto auxiliary MDIO bus");
+MODULE_LICENSE("GPL v2");