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