xref: /linux/drivers/net/dsa/mxl862xx/mxl862xx.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*23794becSDaniel Golle // SPDX-License-Identifier: GPL-2.0-or-later
2*23794becSDaniel Golle /*
3*23794becSDaniel Golle  * Driver for MaxLinear MxL862xx switch family
4*23794becSDaniel Golle  *
5*23794becSDaniel Golle  * Copyright (C) 2024 MaxLinear Inc.
6*23794becSDaniel Golle  * Copyright (C) 2025 John Crispin <john@phrozen.org>
7*23794becSDaniel Golle  * Copyright (C) 2025 Daniel Golle <daniel@makrotopia.org>
8*23794becSDaniel Golle  */
9*23794becSDaniel Golle 
10*23794becSDaniel Golle #include <linux/module.h>
11*23794becSDaniel Golle #include <linux/delay.h>
12*23794becSDaniel Golle #include <linux/of_device.h>
13*23794becSDaniel Golle #include <linux/of_mdio.h>
14*23794becSDaniel Golle #include <linux/phy.h>
15*23794becSDaniel Golle #include <linux/phylink.h>
16*23794becSDaniel Golle #include <net/dsa.h>
17*23794becSDaniel Golle 
18*23794becSDaniel Golle #include "mxl862xx.h"
19*23794becSDaniel Golle #include "mxl862xx-api.h"
20*23794becSDaniel Golle #include "mxl862xx-cmd.h"
21*23794becSDaniel Golle #include "mxl862xx-host.h"
22*23794becSDaniel Golle 
23*23794becSDaniel Golle #define MXL862XX_API_WRITE(dev, cmd, data) \
24*23794becSDaniel Golle 	mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), false, false)
25*23794becSDaniel Golle #define MXL862XX_API_READ(dev, cmd, data) \
26*23794becSDaniel Golle 	mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, false)
27*23794becSDaniel Golle #define MXL862XX_API_READ_QUIET(dev, cmd, data) \
28*23794becSDaniel Golle 	mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, true)
29*23794becSDaniel Golle 
30*23794becSDaniel Golle #define MXL862XX_SDMA_PCTRLP(p)		(0xbc0 + ((p) * 0x6))
31*23794becSDaniel Golle #define MXL862XX_SDMA_PCTRL_EN		BIT(0)
32*23794becSDaniel Golle 
33*23794becSDaniel Golle #define MXL862XX_FDMA_PCTRLP(p)		(0xa80 + ((p) * 0x6))
34*23794becSDaniel Golle #define MXL862XX_FDMA_PCTRL_EN		BIT(0)
35*23794becSDaniel Golle 
36*23794becSDaniel Golle #define MXL862XX_READY_TIMEOUT_MS	10000
37*23794becSDaniel Golle #define MXL862XX_READY_POLL_MS		100
38*23794becSDaniel Golle 
39*23794becSDaniel Golle static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,
40*23794becSDaniel Golle 						       int port,
41*23794becSDaniel Golle 						       enum dsa_tag_protocol m)
42*23794becSDaniel Golle {
43*23794becSDaniel Golle 	return DSA_TAG_PROTO_MXL862;
44*23794becSDaniel Golle }
45*23794becSDaniel Golle 
46*23794becSDaniel Golle /* PHY access via firmware relay */
47*23794becSDaniel Golle static int mxl862xx_phy_read_mmd(struct mxl862xx_priv *priv, int port,
48*23794becSDaniel Golle 				 int devadd, int reg)
49*23794becSDaniel Golle {
50*23794becSDaniel Golle 	struct mdio_relay_data param = {
51*23794becSDaniel Golle 		.phy = port,
52*23794becSDaniel Golle 		.mmd = devadd,
53*23794becSDaniel Golle 		.reg = cpu_to_le16(reg),
54*23794becSDaniel Golle 	};
55*23794becSDaniel Golle 	int ret;
56*23794becSDaniel Golle 
57*23794becSDaniel Golle 	ret = MXL862XX_API_READ(priv, INT_GPHY_READ, param);
58*23794becSDaniel Golle 	if (ret)
59*23794becSDaniel Golle 		return ret;
60*23794becSDaniel Golle 
61*23794becSDaniel Golle 	return le16_to_cpu(param.data);
62*23794becSDaniel Golle }
63*23794becSDaniel Golle 
64*23794becSDaniel Golle static int mxl862xx_phy_write_mmd(struct mxl862xx_priv *priv, int port,
65*23794becSDaniel Golle 				  int devadd, int reg, u16 data)
66*23794becSDaniel Golle {
67*23794becSDaniel Golle 	struct mdio_relay_data param = {
68*23794becSDaniel Golle 		.phy = port,
69*23794becSDaniel Golle 		.mmd = devadd,
70*23794becSDaniel Golle 		.reg = cpu_to_le16(reg),
71*23794becSDaniel Golle 		.data = cpu_to_le16(data),
72*23794becSDaniel Golle 	};
73*23794becSDaniel Golle 
74*23794becSDaniel Golle 	return MXL862XX_API_WRITE(priv, INT_GPHY_WRITE, param);
75*23794becSDaniel Golle }
76*23794becSDaniel Golle 
77*23794becSDaniel Golle static int mxl862xx_phy_read_mii_bus(struct mii_bus *bus, int port, int regnum)
78*23794becSDaniel Golle {
79*23794becSDaniel Golle 	return mxl862xx_phy_read_mmd(bus->priv, port, 0, regnum);
80*23794becSDaniel Golle }
81*23794becSDaniel Golle 
82*23794becSDaniel Golle static int mxl862xx_phy_write_mii_bus(struct mii_bus *bus, int port,
83*23794becSDaniel Golle 				      int regnum, u16 val)
84*23794becSDaniel Golle {
85*23794becSDaniel Golle 	return mxl862xx_phy_write_mmd(bus->priv, port, 0, regnum, val);
86*23794becSDaniel Golle }
87*23794becSDaniel Golle 
88*23794becSDaniel Golle static int mxl862xx_phy_read_c45_mii_bus(struct mii_bus *bus, int port,
89*23794becSDaniel Golle 					 int devadd, int regnum)
90*23794becSDaniel Golle {
91*23794becSDaniel Golle 	return mxl862xx_phy_read_mmd(bus->priv, port, devadd, regnum);
92*23794becSDaniel Golle }
93*23794becSDaniel Golle 
94*23794becSDaniel Golle static int mxl862xx_phy_write_c45_mii_bus(struct mii_bus *bus, int port,
95*23794becSDaniel Golle 					  int devadd, int regnum, u16 val)
96*23794becSDaniel Golle {
97*23794becSDaniel Golle 	return mxl862xx_phy_write_mmd(bus->priv, port, devadd, regnum, val);
98*23794becSDaniel Golle }
99*23794becSDaniel Golle 
100*23794becSDaniel Golle static int mxl862xx_wait_ready(struct dsa_switch *ds)
101*23794becSDaniel Golle {
102*23794becSDaniel Golle 	struct mxl862xx_sys_fw_image_version ver = {};
103*23794becSDaniel Golle 	unsigned long start = jiffies, timeout;
104*23794becSDaniel Golle 	struct mxl862xx_priv *priv = ds->priv;
105*23794becSDaniel Golle 	struct mxl862xx_cfg cfg = {};
106*23794becSDaniel Golle 	int ret;
107*23794becSDaniel Golle 
108*23794becSDaniel Golle 	timeout = start + msecs_to_jiffies(MXL862XX_READY_TIMEOUT_MS);
109*23794becSDaniel Golle 	msleep(2000); /* it always takes at least 2 seconds */
110*23794becSDaniel Golle 	do {
111*23794becSDaniel Golle 		ret = MXL862XX_API_READ_QUIET(priv, SYS_MISC_FW_VERSION, ver);
112*23794becSDaniel Golle 		if (ret || !ver.iv_major)
113*23794becSDaniel Golle 			goto not_ready_yet;
114*23794becSDaniel Golle 
115*23794becSDaniel Golle 		/* being able to perform CFGGET indicates that
116*23794becSDaniel Golle 		 * the firmware is ready
117*23794becSDaniel Golle 		 */
118*23794becSDaniel Golle 		ret = MXL862XX_API_READ_QUIET(priv,
119*23794becSDaniel Golle 					      MXL862XX_COMMON_CFGGET,
120*23794becSDaniel Golle 					      cfg);
121*23794becSDaniel Golle 		if (ret)
122*23794becSDaniel Golle 			goto not_ready_yet;
123*23794becSDaniel Golle 
124*23794becSDaniel Golle 		dev_info(ds->dev, "switch ready after %ums, firmware %u.%u.%u (build %u)\n",
125*23794becSDaniel Golle 			 jiffies_to_msecs(jiffies - start),
126*23794becSDaniel Golle 			 ver.iv_major, ver.iv_minor,
127*23794becSDaniel Golle 			 le16_to_cpu(ver.iv_revision),
128*23794becSDaniel Golle 			 le32_to_cpu(ver.iv_build_num));
129*23794becSDaniel Golle 		return 0;
130*23794becSDaniel Golle 
131*23794becSDaniel Golle not_ready_yet:
132*23794becSDaniel Golle 		msleep(MXL862XX_READY_POLL_MS);
133*23794becSDaniel Golle 	} while (time_before(jiffies, timeout));
134*23794becSDaniel Golle 
135*23794becSDaniel Golle 	dev_err(ds->dev, "switch not responding after reset\n");
136*23794becSDaniel Golle 	return -ETIMEDOUT;
137*23794becSDaniel Golle }
138*23794becSDaniel Golle 
139*23794becSDaniel Golle static int mxl862xx_setup_mdio(struct dsa_switch *ds)
140*23794becSDaniel Golle {
141*23794becSDaniel Golle 	struct mxl862xx_priv *priv = ds->priv;
142*23794becSDaniel Golle 	struct device *dev = ds->dev;
143*23794becSDaniel Golle 	struct device_node *mdio_np;
144*23794becSDaniel Golle 	struct mii_bus *bus;
145*23794becSDaniel Golle 	int ret;
146*23794becSDaniel Golle 
147*23794becSDaniel Golle 	bus = devm_mdiobus_alloc(dev);
148*23794becSDaniel Golle 	if (!bus)
149*23794becSDaniel Golle 		return -ENOMEM;
150*23794becSDaniel Golle 
151*23794becSDaniel Golle 	bus->priv = priv;
152*23794becSDaniel Golle 	ds->user_mii_bus = bus;
153*23794becSDaniel Golle 	bus->name = KBUILD_MODNAME "-mii";
154*23794becSDaniel Golle 	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
155*23794becSDaniel Golle 	bus->read_c45 = mxl862xx_phy_read_c45_mii_bus;
156*23794becSDaniel Golle 	bus->write_c45 = mxl862xx_phy_write_c45_mii_bus;
157*23794becSDaniel Golle 	bus->read = mxl862xx_phy_read_mii_bus;
158*23794becSDaniel Golle 	bus->write = mxl862xx_phy_write_mii_bus;
159*23794becSDaniel Golle 	bus->parent = dev;
160*23794becSDaniel Golle 	bus->phy_mask = ~ds->phys_mii_mask;
161*23794becSDaniel Golle 
162*23794becSDaniel Golle 	mdio_np = of_get_child_by_name(dev->of_node, "mdio");
163*23794becSDaniel Golle 	if (!mdio_np)
164*23794becSDaniel Golle 		return -ENODEV;
165*23794becSDaniel Golle 
166*23794becSDaniel Golle 	ret = devm_of_mdiobus_register(dev, bus, mdio_np);
167*23794becSDaniel Golle 	of_node_put(mdio_np);
168*23794becSDaniel Golle 
169*23794becSDaniel Golle 	return ret;
170*23794becSDaniel Golle }
171*23794becSDaniel Golle 
172*23794becSDaniel Golle static int mxl862xx_setup(struct dsa_switch *ds)
173*23794becSDaniel Golle {
174*23794becSDaniel Golle 	struct mxl862xx_priv *priv = ds->priv;
175*23794becSDaniel Golle 	int ret;
176*23794becSDaniel Golle 
177*23794becSDaniel Golle 	ret = mxl862xx_reset(priv);
178*23794becSDaniel Golle 	if (ret)
179*23794becSDaniel Golle 		return ret;
180*23794becSDaniel Golle 
181*23794becSDaniel Golle 	ret = mxl862xx_wait_ready(ds);
182*23794becSDaniel Golle 	if (ret)
183*23794becSDaniel Golle 		return ret;
184*23794becSDaniel Golle 
185*23794becSDaniel Golle 	return mxl862xx_setup_mdio(ds);
186*23794becSDaniel Golle }
187*23794becSDaniel Golle 
188*23794becSDaniel Golle static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable)
189*23794becSDaniel Golle {
190*23794becSDaniel Golle 	struct mxl862xx_register_mod sdma = {
191*23794becSDaniel Golle 		.addr = cpu_to_le16(MXL862XX_SDMA_PCTRLP(port)),
192*23794becSDaniel Golle 		.data = cpu_to_le16(enable ? MXL862XX_SDMA_PCTRL_EN : 0),
193*23794becSDaniel Golle 		.mask = cpu_to_le16(MXL862XX_SDMA_PCTRL_EN),
194*23794becSDaniel Golle 	};
195*23794becSDaniel Golle 	struct mxl862xx_register_mod fdma = {
196*23794becSDaniel Golle 		.addr = cpu_to_le16(MXL862XX_FDMA_PCTRLP(port)),
197*23794becSDaniel Golle 		.data = cpu_to_le16(enable ? MXL862XX_FDMA_PCTRL_EN : 0),
198*23794becSDaniel Golle 		.mask = cpu_to_le16(MXL862XX_FDMA_PCTRL_EN),
199*23794becSDaniel Golle 	};
200*23794becSDaniel Golle 	int ret;
201*23794becSDaniel Golle 
202*23794becSDaniel Golle 	ret = MXL862XX_API_WRITE(ds->priv, MXL862XX_COMMON_REGISTERMOD, sdma);
203*23794becSDaniel Golle 	if (ret)
204*23794becSDaniel Golle 		return ret;
205*23794becSDaniel Golle 
206*23794becSDaniel Golle 	return MXL862XX_API_WRITE(ds->priv, MXL862XX_COMMON_REGISTERMOD, fdma);
207*23794becSDaniel Golle }
208*23794becSDaniel Golle 
209*23794becSDaniel Golle static int mxl862xx_port_enable(struct dsa_switch *ds, int port,
210*23794becSDaniel Golle 				struct phy_device *phydev)
211*23794becSDaniel Golle {
212*23794becSDaniel Golle 	return mxl862xx_port_state(ds, port, true);
213*23794becSDaniel Golle }
214*23794becSDaniel Golle 
215*23794becSDaniel Golle static void mxl862xx_port_disable(struct dsa_switch *ds, int port)
216*23794becSDaniel Golle {
217*23794becSDaniel Golle 	if (mxl862xx_port_state(ds, port, false))
218*23794becSDaniel Golle 		dev_err(ds->dev, "failed to disable port %d\n", port);
219*23794becSDaniel Golle }
220*23794becSDaniel Golle 
221*23794becSDaniel Golle static void mxl862xx_port_fast_age(struct dsa_switch *ds, int port)
222*23794becSDaniel Golle {
223*23794becSDaniel Golle 	struct mxl862xx_mac_table_clear param = {
224*23794becSDaniel Golle 		.type = MXL862XX_MAC_CLEAR_PHY_PORT,
225*23794becSDaniel Golle 		.port_id = port,
226*23794becSDaniel Golle 	};
227*23794becSDaniel Golle 
228*23794becSDaniel Golle 	if (MXL862XX_API_WRITE(ds->priv, MXL862XX_MAC_TABLECLEARCOND, param))
229*23794becSDaniel Golle 		dev_err(ds->dev, "failed to clear fdb on port %d\n", port);
230*23794becSDaniel Golle }
231*23794becSDaniel Golle 
232*23794becSDaniel Golle static int mxl862xx_configure_ctp_port(struct dsa_switch *ds, int port,
233*23794becSDaniel Golle 				       u16 first_ctp_port_id,
234*23794becSDaniel Golle 				       u16 number_of_ctp_ports)
235*23794becSDaniel Golle {
236*23794becSDaniel Golle 	struct mxl862xx_ctp_port_assignment ctp_assign = {
237*23794becSDaniel Golle 		.logical_port_id = port,
238*23794becSDaniel Golle 		.first_ctp_port_id = cpu_to_le16(first_ctp_port_id),
239*23794becSDaniel Golle 		.number_of_ctp_port = cpu_to_le16(number_of_ctp_ports),
240*23794becSDaniel Golle 		.mode = cpu_to_le32(MXL862XX_LOGICAL_PORT_ETHERNET),
241*23794becSDaniel Golle 	};
242*23794becSDaniel Golle 
243*23794becSDaniel Golle 	return MXL862XX_API_WRITE(ds->priv, MXL862XX_CTP_PORTASSIGNMENTSET,
244*23794becSDaniel Golle 				  ctp_assign);
245*23794becSDaniel Golle }
246*23794becSDaniel Golle 
247*23794becSDaniel Golle static int mxl862xx_configure_sp_tag_proto(struct dsa_switch *ds, int port,
248*23794becSDaniel Golle 					   bool enable)
249*23794becSDaniel Golle {
250*23794becSDaniel Golle 	struct mxl862xx_ss_sp_tag tag = {
251*23794becSDaniel Golle 		.pid = port,
252*23794becSDaniel Golle 		.mask = MXL862XX_SS_SP_TAG_MASK_RX | MXL862XX_SS_SP_TAG_MASK_TX,
253*23794becSDaniel Golle 		.rx = enable ? MXL862XX_SS_SP_TAG_RX_TAG_NO_INSERT :
254*23794becSDaniel Golle 			       MXL862XX_SS_SP_TAG_RX_NO_TAG_INSERT,
255*23794becSDaniel Golle 		.tx = enable ? MXL862XX_SS_SP_TAG_TX_TAG_NO_REMOVE :
256*23794becSDaniel Golle 			       MXL862XX_SS_SP_TAG_TX_TAG_REMOVE,
257*23794becSDaniel Golle 	};
258*23794becSDaniel Golle 
259*23794becSDaniel Golle 	return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
260*23794becSDaniel Golle }
261*23794becSDaniel Golle 
262*23794becSDaniel Golle static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port)
263*23794becSDaniel Golle {
264*23794becSDaniel Golle 	struct mxl862xx_bridge_port_config br_port_cfg = {};
265*23794becSDaniel Golle 	struct mxl862xx_priv *priv = ds->priv;
266*23794becSDaniel Golle 	u16 bridge_port_map = 0;
267*23794becSDaniel Golle 	struct dsa_port *dp;
268*23794becSDaniel Golle 
269*23794becSDaniel Golle 	/* CPU port bridge setup */
270*23794becSDaniel Golle 	br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
271*23794becSDaniel Golle 				       MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
272*23794becSDaniel Golle 				       MXL862XX_BRIDGE_PORT_CONFIG_MASK_VLAN_BASED_MAC_LEARNING);
273*23794becSDaniel Golle 
274*23794becSDaniel Golle 	br_port_cfg.bridge_port_id = cpu_to_le16(port);
275*23794becSDaniel Golle 	br_port_cfg.src_mac_learning_disable = false;
276*23794becSDaniel Golle 	br_port_cfg.vlan_src_mac_vid_enable = true;
277*23794becSDaniel Golle 	br_port_cfg.vlan_dst_mac_vid_enable = true;
278*23794becSDaniel Golle 
279*23794becSDaniel Golle 	/* include all assigned user ports in the CPU portmap */
280*23794becSDaniel Golle 	dsa_switch_for_each_user_port(dp, ds) {
281*23794becSDaniel Golle 		/* it's safe to rely on cpu_dp being valid for user ports */
282*23794becSDaniel Golle 		if (dp->cpu_dp->index != port)
283*23794becSDaniel Golle 			continue;
284*23794becSDaniel Golle 
285*23794becSDaniel Golle 		bridge_port_map |= BIT(dp->index);
286*23794becSDaniel Golle 	}
287*23794becSDaniel Golle 	br_port_cfg.bridge_port_map[0] |= cpu_to_le16(bridge_port_map);
288*23794becSDaniel Golle 
289*23794becSDaniel Golle 	return MXL862XX_API_WRITE(priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
290*23794becSDaniel Golle }
291*23794becSDaniel Golle 
292*23794becSDaniel Golle static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port)
293*23794becSDaniel Golle {
294*23794becSDaniel Golle 	struct mxl862xx_bridge_port_config br_port_cfg = {};
295*23794becSDaniel Golle 	struct dsa_port *dp = dsa_to_port(ds, port);
296*23794becSDaniel Golle 	struct mxl862xx_bridge_alloc br_alloc = {};
297*23794becSDaniel Golle 	int ret;
298*23794becSDaniel Golle 
299*23794becSDaniel Golle 	ret = MXL862XX_API_READ(ds->priv, MXL862XX_BRIDGE_ALLOC, br_alloc);
300*23794becSDaniel Golle 	if (ret) {
301*23794becSDaniel Golle 		dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
302*23794becSDaniel Golle 		return ret;
303*23794becSDaniel Golle 	}
304*23794becSDaniel Golle 
305*23794becSDaniel Golle 	br_port_cfg.bridge_id = br_alloc.bridge_id;
306*23794becSDaniel Golle 	br_port_cfg.bridge_port_id = cpu_to_le16(port);
307*23794becSDaniel Golle 	br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
308*23794becSDaniel Golle 				       MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
309*23794becSDaniel Golle 				       MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
310*23794becSDaniel Golle 				       MXL862XX_BRIDGE_PORT_CONFIG_MASK_VLAN_BASED_MAC_LEARNING);
311*23794becSDaniel Golle 	br_port_cfg.src_mac_learning_disable = true;
312*23794becSDaniel Golle 	br_port_cfg.vlan_src_mac_vid_enable = false;
313*23794becSDaniel Golle 	br_port_cfg.vlan_dst_mac_vid_enable = false;
314*23794becSDaniel Golle 	/* As this function is only called for user ports it is safe to rely on
315*23794becSDaniel Golle 	 * cpu_dp being valid
316*23794becSDaniel Golle 	 */
317*23794becSDaniel Golle 	br_port_cfg.bridge_port_map[0] = cpu_to_le16(BIT(dp->cpu_dp->index));
318*23794becSDaniel Golle 
319*23794becSDaniel Golle 	return MXL862XX_API_WRITE(ds->priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
320*23794becSDaniel Golle }
321*23794becSDaniel Golle 
322*23794becSDaniel Golle static int mxl862xx_port_setup(struct dsa_switch *ds, int port)
323*23794becSDaniel Golle {
324*23794becSDaniel Golle 	struct dsa_port *dp = dsa_to_port(ds, port);
325*23794becSDaniel Golle 	bool is_cpu_port = dsa_port_is_cpu(dp);
326*23794becSDaniel Golle 	int ret;
327*23794becSDaniel Golle 
328*23794becSDaniel Golle 	/* disable port and flush MAC entries */
329*23794becSDaniel Golle 	ret = mxl862xx_port_state(ds, port, false);
330*23794becSDaniel Golle 	if (ret)
331*23794becSDaniel Golle 		return ret;
332*23794becSDaniel Golle 
333*23794becSDaniel Golle 	mxl862xx_port_fast_age(ds, port);
334*23794becSDaniel Golle 
335*23794becSDaniel Golle 	/* skip setup for unused and DSA ports */
336*23794becSDaniel Golle 	if (dsa_port_is_unused(dp) ||
337*23794becSDaniel Golle 	    dsa_port_is_dsa(dp))
338*23794becSDaniel Golle 		return 0;
339*23794becSDaniel Golle 
340*23794becSDaniel Golle 	/* configure tag protocol */
341*23794becSDaniel Golle 	ret = mxl862xx_configure_sp_tag_proto(ds, port, is_cpu_port);
342*23794becSDaniel Golle 	if (ret)
343*23794becSDaniel Golle 		return ret;
344*23794becSDaniel Golle 
345*23794becSDaniel Golle 	/* assign CTP port IDs */
346*23794becSDaniel Golle 	ret = mxl862xx_configure_ctp_port(ds, port, port,
347*23794becSDaniel Golle 					  is_cpu_port ? 32 - port : 1);
348*23794becSDaniel Golle 	if (ret)
349*23794becSDaniel Golle 		return ret;
350*23794becSDaniel Golle 
351*23794becSDaniel Golle 	if (is_cpu_port)
352*23794becSDaniel Golle 		/* assign user ports to CPU port bridge */
353*23794becSDaniel Golle 		return mxl862xx_setup_cpu_bridge(ds, port);
354*23794becSDaniel Golle 
355*23794becSDaniel Golle 	/* setup single-port bridge for user ports */
356*23794becSDaniel Golle 	return mxl862xx_add_single_port_bridge(ds, port);
357*23794becSDaniel Golle }
358*23794becSDaniel Golle 
359*23794becSDaniel Golle static void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
360*23794becSDaniel Golle 				      struct phylink_config *config)
361*23794becSDaniel Golle {
362*23794becSDaniel Golle 	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 |
363*23794becSDaniel Golle 				   MAC_100 | MAC_1000 | MAC_2500FD;
364*23794becSDaniel Golle 
365*23794becSDaniel Golle 	__set_bit(PHY_INTERFACE_MODE_INTERNAL,
366*23794becSDaniel Golle 		  config->supported_interfaces);
367*23794becSDaniel Golle }
368*23794becSDaniel Golle 
369*23794becSDaniel Golle static const struct dsa_switch_ops mxl862xx_switch_ops = {
370*23794becSDaniel Golle 	.get_tag_protocol = mxl862xx_get_tag_protocol,
371*23794becSDaniel Golle 	.setup = mxl862xx_setup,
372*23794becSDaniel Golle 	.port_setup = mxl862xx_port_setup,
373*23794becSDaniel Golle 	.phylink_get_caps = mxl862xx_phylink_get_caps,
374*23794becSDaniel Golle 	.port_enable = mxl862xx_port_enable,
375*23794becSDaniel Golle 	.port_disable = mxl862xx_port_disable,
376*23794becSDaniel Golle 	.port_fast_age = mxl862xx_port_fast_age,
377*23794becSDaniel Golle };
378*23794becSDaniel Golle 
379*23794becSDaniel Golle static void mxl862xx_phylink_mac_config(struct phylink_config *config,
380*23794becSDaniel Golle 					unsigned int mode,
381*23794becSDaniel Golle 					const struct phylink_link_state *state)
382*23794becSDaniel Golle {
383*23794becSDaniel Golle }
384*23794becSDaniel Golle 
385*23794becSDaniel Golle static void mxl862xx_phylink_mac_link_down(struct phylink_config *config,
386*23794becSDaniel Golle 					   unsigned int mode,
387*23794becSDaniel Golle 					   phy_interface_t interface)
388*23794becSDaniel Golle {
389*23794becSDaniel Golle }
390*23794becSDaniel Golle 
391*23794becSDaniel Golle static void mxl862xx_phylink_mac_link_up(struct phylink_config *config,
392*23794becSDaniel Golle 					 struct phy_device *phydev,
393*23794becSDaniel Golle 					 unsigned int mode,
394*23794becSDaniel Golle 					 phy_interface_t interface,
395*23794becSDaniel Golle 					 int speed, int duplex,
396*23794becSDaniel Golle 					 bool tx_pause, bool rx_pause)
397*23794becSDaniel Golle {
398*23794becSDaniel Golle }
399*23794becSDaniel Golle 
400*23794becSDaniel Golle static const struct phylink_mac_ops mxl862xx_phylink_mac_ops = {
401*23794becSDaniel Golle 	.mac_config = mxl862xx_phylink_mac_config,
402*23794becSDaniel Golle 	.mac_link_down = mxl862xx_phylink_mac_link_down,
403*23794becSDaniel Golle 	.mac_link_up = mxl862xx_phylink_mac_link_up,
404*23794becSDaniel Golle };
405*23794becSDaniel Golle 
406*23794becSDaniel Golle static int mxl862xx_probe(struct mdio_device *mdiodev)
407*23794becSDaniel Golle {
408*23794becSDaniel Golle 	struct device *dev = &mdiodev->dev;
409*23794becSDaniel Golle 	struct mxl862xx_priv *priv;
410*23794becSDaniel Golle 	struct dsa_switch *ds;
411*23794becSDaniel Golle 
412*23794becSDaniel Golle 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
413*23794becSDaniel Golle 	if (!priv)
414*23794becSDaniel Golle 		return -ENOMEM;
415*23794becSDaniel Golle 
416*23794becSDaniel Golle 	priv->mdiodev = mdiodev;
417*23794becSDaniel Golle 
418*23794becSDaniel Golle 	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
419*23794becSDaniel Golle 	if (!ds)
420*23794becSDaniel Golle 		return -ENOMEM;
421*23794becSDaniel Golle 
422*23794becSDaniel Golle 	priv->ds = ds;
423*23794becSDaniel Golle 	ds->dev = dev;
424*23794becSDaniel Golle 	ds->priv = priv;
425*23794becSDaniel Golle 	ds->ops = &mxl862xx_switch_ops;
426*23794becSDaniel Golle 	ds->phylink_mac_ops = &mxl862xx_phylink_mac_ops;
427*23794becSDaniel Golle 	ds->num_ports = MXL862XX_MAX_PORTS;
428*23794becSDaniel Golle 
429*23794becSDaniel Golle 	dev_set_drvdata(dev, ds);
430*23794becSDaniel Golle 
431*23794becSDaniel Golle 	return dsa_register_switch(ds);
432*23794becSDaniel Golle }
433*23794becSDaniel Golle 
434*23794becSDaniel Golle static void mxl862xx_remove(struct mdio_device *mdiodev)
435*23794becSDaniel Golle {
436*23794becSDaniel Golle 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
437*23794becSDaniel Golle 
438*23794becSDaniel Golle 	if (!ds)
439*23794becSDaniel Golle 		return;
440*23794becSDaniel Golle 
441*23794becSDaniel Golle 	dsa_unregister_switch(ds);
442*23794becSDaniel Golle }
443*23794becSDaniel Golle 
444*23794becSDaniel Golle static void mxl862xx_shutdown(struct mdio_device *mdiodev)
445*23794becSDaniel Golle {
446*23794becSDaniel Golle 	struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
447*23794becSDaniel Golle 
448*23794becSDaniel Golle 	if (!ds)
449*23794becSDaniel Golle 		return;
450*23794becSDaniel Golle 
451*23794becSDaniel Golle 	dsa_switch_shutdown(ds);
452*23794becSDaniel Golle 
453*23794becSDaniel Golle 	dev_set_drvdata(&mdiodev->dev, NULL);
454*23794becSDaniel Golle }
455*23794becSDaniel Golle 
456*23794becSDaniel Golle static const struct of_device_id mxl862xx_of_match[] = {
457*23794becSDaniel Golle 	{ .compatible = "maxlinear,mxl86282" },
458*23794becSDaniel Golle 	{ .compatible = "maxlinear,mxl86252" },
459*23794becSDaniel Golle 	{ /* sentinel */ }
460*23794becSDaniel Golle };
461*23794becSDaniel Golle MODULE_DEVICE_TABLE(of, mxl862xx_of_match);
462*23794becSDaniel Golle 
463*23794becSDaniel Golle static struct mdio_driver mxl862xx_driver = {
464*23794becSDaniel Golle 	.probe  = mxl862xx_probe,
465*23794becSDaniel Golle 	.remove = mxl862xx_remove,
466*23794becSDaniel Golle 	.shutdown = mxl862xx_shutdown,
467*23794becSDaniel Golle 	.mdiodrv.driver = {
468*23794becSDaniel Golle 		.name = "mxl862xx",
469*23794becSDaniel Golle 		.of_match_table = mxl862xx_of_match,
470*23794becSDaniel Golle 	},
471*23794becSDaniel Golle };
472*23794becSDaniel Golle 
473*23794becSDaniel Golle mdio_module_driver(mxl862xx_driver);
474*23794becSDaniel Golle 
475*23794becSDaniel Golle MODULE_DESCRIPTION("Driver for MaxLinear MxL862xx switch family");
476*23794becSDaniel Golle MODULE_LICENSE("GPL");
477