1637 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Broadcom Starfighter 2 DSA switch driver4 *5 * Copyright (C) 2014, Broadcom Corporation6 */7 8#include <linux/list.h>9#include <linux/module.h>10#include <linux/netdevice.h>11#include <linux/interrupt.h>12#include <linux/platform_device.h>13#include <linux/phy.h>14#include <linux/phy_fixed.h>15#include <linux/phylink.h>16#include <linux/mii.h>17#include <linux/clk.h>18#include <linux/of.h>19#include <linux/of_irq.h>20#include <linux/of_address.h>21#include <linux/of_net.h>22#include <linux/of_mdio.h>23#include <net/dsa.h>24#include <linux/ethtool.h>25#include <linux/if_bridge.h>26#include <linux/brcmphy.h>27#include <linux/etherdevice.h>28#include <linux/platform_data/b53.h>29 30#include "bcm_sf2.h"31#include "bcm_sf2_regs.h"32#include "b53/b53_priv.h"33#include "b53/b53_regs.h"34 35static u16 bcm_sf2_reg_rgmii_cntrl(struct bcm_sf2_priv *priv, int port)36{37 switch (priv->type) {38 case BCM4908_DEVICE_ID:39 switch (port) {40 case 7:41 return REG_RGMII_11_CNTRL;42 default:43 break;44 }45 break;46 default:47 switch (port) {48 case 0:49 return REG_RGMII_0_CNTRL;50 case 1:51 return REG_RGMII_1_CNTRL;52 case 2:53 return REG_RGMII_2_CNTRL;54 default:55 break;56 }57 }58 59 WARN_ONCE(1, "Unsupported port %d\n", port);60 61 /* RO fallback reg */62 return REG_SWITCH_STATUS;63}64 65static u16 bcm_sf2_reg_led_base(struct bcm_sf2_priv *priv, int port)66{67 switch (port) {68 case 0:69 return REG_LED_0_CNTRL;70 case 1:71 return REG_LED_1_CNTRL;72 case 2:73 return REG_LED_2_CNTRL;74 }75 76 switch (priv->type) {77 case BCM4908_DEVICE_ID:78 switch (port) {79 case 3:80 return REG_LED_3_CNTRL;81 case 7:82 return REG_LED_4_CNTRL;83 default:84 break;85 }86 break;87 default:88 break;89 }90 91 WARN_ONCE(1, "Unsupported port %d\n", port);92 93 /* RO fallback reg */94 return REG_SWITCH_STATUS;95}96 97static u32 bcm_sf2_port_override_offset(struct bcm_sf2_priv *priv, int port)98{99 switch (priv->type) {100 case BCM4908_DEVICE_ID:101 case BCM7445_DEVICE_ID:102 return port == 8 ? CORE_STS_OVERRIDE_IMP :103 CORE_STS_OVERRIDE_GMIIP_PORT(port);104 case BCM7278_DEVICE_ID:105 return port == 8 ? CORE_STS_OVERRIDE_IMP2 :106 CORE_STS_OVERRIDE_GMIIP2_PORT(port);107 default:108 WARN_ONCE(1, "Unsupported device: %d\n", priv->type);109 }110 111 /* RO fallback register */112 return REG_SWITCH_STATUS;113}114 115/* Return the number of active ports, not counting the IMP (CPU) port */116static unsigned int bcm_sf2_num_active_ports(struct dsa_switch *ds)117{118 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);119 unsigned int port, count = 0;120 121 for (port = 0; port < ds->num_ports; port++) {122 if (dsa_is_cpu_port(ds, port))123 continue;124 if (priv->port_sts[port].enabled)125 count++;126 }127 128 return count;129}130 131static void bcm_sf2_recalc_clock(struct dsa_switch *ds)132{133 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);134 unsigned long new_rate;135 unsigned int ports_active;136 /* Frequenty in Mhz */137 static const unsigned long rate_table[] = {138 59220000,139 60820000,140 62500000,141 62500000,142 };143 144 ports_active = bcm_sf2_num_active_ports(ds);145 if (ports_active == 0 || !priv->clk_mdiv)146 return;147 148 /* If we overflow our table, just use the recommended operational149 * frequency150 */151 if (ports_active > ARRAY_SIZE(rate_table))152 new_rate = 90000000;153 else154 new_rate = rate_table[ports_active - 1];155 clk_set_rate(priv->clk_mdiv, new_rate);156}157 158static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)159{160 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);161 unsigned int i;162 u32 reg;163 164 /* Enable the port memories */165 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);166 reg &= ~P_TXQ_PSM_VDD(port);167 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);168 169 /* Enable forwarding */170 core_writel(priv, SW_FWDG_EN, CORE_SWMODE);171 172 /* Enable IMP port in dumb mode */173 reg = core_readl(priv, CORE_SWITCH_CTRL);174 reg |= MII_DUMB_FWDG_EN;175 core_writel(priv, reg, CORE_SWITCH_CTRL);176 177 /* Configure Traffic Class to QoS mapping, allow each priority to map178 * to a different queue number179 */180 reg = core_readl(priv, CORE_PORT_TC2_QOS_MAP_PORT(port));181 for (i = 0; i < SF2_NUM_EGRESS_QUEUES; i++)182 reg |= i << (PRT_TO_QID_SHIFT * i);183 core_writel(priv, reg, CORE_PORT_TC2_QOS_MAP_PORT(port));184 185 b53_brcm_hdr_setup(ds, port);186 187 if (port == 8) {188 /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */189 reg = core_readl(priv, CORE_IMP_CTL);190 reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);191 reg &= ~(RX_DIS | TX_DIS);192 core_writel(priv, reg, CORE_IMP_CTL);193 } else {194 reg = core_readl(priv, CORE_G_PCTL_PORT(port));195 reg &= ~(RX_DIS | TX_DIS);196 core_writel(priv, reg, CORE_G_PCTL_PORT(port));197 }198 199 priv->port_sts[port].enabled = true;200}201 202static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)203{204 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);205 u32 reg;206 207 reg = reg_readl(priv, REG_SPHY_CNTRL);208 if (enable) {209 reg |= PHY_RESET;210 reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | IDDQ_GLOBAL_PWR | CK25_DIS);211 reg_writel(priv, reg, REG_SPHY_CNTRL);212 udelay(21);213 reg = reg_readl(priv, REG_SPHY_CNTRL);214 reg &= ~PHY_RESET;215 } else {216 reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET;217 reg_writel(priv, reg, REG_SPHY_CNTRL);218 mdelay(1);219 reg |= CK25_DIS;220 }221 reg_writel(priv, reg, REG_SPHY_CNTRL);222 223 /* Use PHY-driven LED signaling */224 if (!enable) {225 u16 led_ctrl = bcm_sf2_reg_led_base(priv, 0);226 227 if (priv->type == BCM7278_DEVICE_ID ||228 priv->type == BCM7445_DEVICE_ID) {229 reg = reg_led_readl(priv, led_ctrl, 0);230 reg |= LED_CNTRL_SPDLNK_SRC_SEL;231 reg_led_writel(priv, reg, led_ctrl, 0);232 }233 }234}235 236static inline void bcm_sf2_port_intr_enable(struct bcm_sf2_priv *priv,237 int port)238{239 unsigned int off;240 241 switch (port) {242 case 7:243 off = P7_IRQ_OFF;244 break;245 case 0:246 /* Port 0 interrupts are located on the first bank */247 intrl2_0_mask_clear(priv, P_IRQ_MASK(P0_IRQ_OFF));248 return;249 default:250 off = P_IRQ_OFF(port);251 break;252 }253 254 intrl2_1_mask_clear(priv, P_IRQ_MASK(off));255}256 257static inline void bcm_sf2_port_intr_disable(struct bcm_sf2_priv *priv,258 int port)259{260 unsigned int off;261 262 switch (port) {263 case 7:264 off = P7_IRQ_OFF;265 break;266 case 0:267 /* Port 0 interrupts are located on the first bank */268 intrl2_0_mask_set(priv, P_IRQ_MASK(P0_IRQ_OFF));269 intrl2_0_writel(priv, P_IRQ_MASK(P0_IRQ_OFF), INTRL2_CPU_CLEAR);270 return;271 default:272 off = P_IRQ_OFF(port);273 break;274 }275 276 intrl2_1_mask_set(priv, P_IRQ_MASK(off));277 intrl2_1_writel(priv, P_IRQ_MASK(off), INTRL2_CPU_CLEAR);278}279 280static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,281 struct phy_device *phy)282{283 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);284 unsigned int i;285 u32 reg;286 287 if (!dsa_is_user_port(ds, port))288 return 0;289 290 priv->port_sts[port].enabled = true;291 292 bcm_sf2_recalc_clock(ds);293 294 /* Clear the memory power down */295 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);296 reg &= ~P_TXQ_PSM_VDD(port);297 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);298 299 /* Enable Broadcom tags for that port if requested */300 if (priv->brcm_tag_mask & BIT(port))301 b53_brcm_hdr_setup(ds, port);302 303 /* Configure Traffic Class to QoS mapping, allow each priority to map304 * to a different queue number305 */306 reg = core_readl(priv, CORE_PORT_TC2_QOS_MAP_PORT(port));307 for (i = 0; i < SF2_NUM_EGRESS_QUEUES; i++)308 reg |= i << (PRT_TO_QID_SHIFT * i);309 core_writel(priv, reg, CORE_PORT_TC2_QOS_MAP_PORT(port));310 311 /* Re-enable the GPHY and re-apply workarounds */312 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1) {313 bcm_sf2_gphy_enable_set(ds, true);314 if (phy) {315 /* if phy_stop() has been called before, phy316 * will be in halted state, and phy_start()317 * will call resume.318 *319 * the resume path does not configure back320 * autoneg settings, and since we hard reset321 * the phy manually here, we need to reset the322 * state machine also.323 */324 phy->state = PHY_READY;325 phy_init_hw(phy);326 }327 }328 329 /* Enable MoCA port interrupts to get notified */330 if (port == priv->moca_port)331 bcm_sf2_port_intr_enable(priv, port);332 333 /* Set per-queue pause threshold to 32 */334 core_writel(priv, 32, CORE_TXQ_THD_PAUSE_QN_PORT(port));335 336 /* Set ACB threshold to 24 */337 for (i = 0; i < SF2_NUM_EGRESS_QUEUES; i++) {338 reg = acb_readl(priv, ACB_QUEUE_CFG(port *339 SF2_NUM_EGRESS_QUEUES + i));340 reg &= ~XOFF_THRESHOLD_MASK;341 reg |= 24;342 acb_writel(priv, reg, ACB_QUEUE_CFG(port *343 SF2_NUM_EGRESS_QUEUES + i));344 }345 346 return b53_enable_port(ds, port, phy);347}348 349static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)350{351 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);352 u32 reg;353 354 /* Disable learning while in WoL mode */355 if (priv->wol_ports_mask & (1 << port)) {356 reg = core_readl(priv, CORE_DIS_LEARN);357 reg |= BIT(port);358 core_writel(priv, reg, CORE_DIS_LEARN);359 return;360 }361 362 if (port == priv->moca_port)363 bcm_sf2_port_intr_disable(priv, port);364 365 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1)366 bcm_sf2_gphy_enable_set(ds, false);367 368 b53_disable_port(ds, port);369 370 /* Power down the port memory */371 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);372 reg |= P_TXQ_PSM_VDD(port);373 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);374 375 priv->port_sts[port].enabled = false;376 377 bcm_sf2_recalc_clock(ds);378}379 380 381static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr,382 int regnum, u16 val)383{384 int ret = 0;385 u32 reg;386 387 reg = reg_readl(priv, REG_SWITCH_CNTRL);388 reg |= MDIO_MASTER_SEL;389 reg_writel(priv, reg, REG_SWITCH_CNTRL);390 391 /* Page << 8 | offset */392 reg = 0x70;393 reg <<= 2;394 core_writel(priv, addr, reg);395 396 /* Page << 8 | offset */397 reg = 0x80 << 8 | regnum << 1;398 reg <<= 2;399 400 if (op)401 ret = core_readl(priv, reg);402 else403 core_writel(priv, val, reg);404 405 reg = reg_readl(priv, REG_SWITCH_CNTRL);406 reg &= ~MDIO_MASTER_SEL;407 reg_writel(priv, reg, REG_SWITCH_CNTRL);408 409 return ret & 0xffff;410}411 412static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)413{414 struct bcm_sf2_priv *priv = bus->priv;415 416 /* Intercept reads from Broadcom pseudo-PHY address, else, send417 * them to our master MDIO bus controller418 */419 if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))420 return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);421 else422 return mdiobus_read_nested(priv->master_mii_bus, addr, regnum);423}424 425static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,426 u16 val)427{428 struct bcm_sf2_priv *priv = bus->priv;429 430 /* Intercept writes to the Broadcom pseudo-PHY address, else,431 * send them to our master MDIO bus controller432 */433 if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))434 return bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);435 else436 return mdiobus_write_nested(priv->master_mii_bus, addr,437 regnum, val);438}439 440static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)441{442 struct dsa_switch *ds = dev_id;443 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);444 445 priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &446 ~priv->irq0_mask;447 intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);448 449 return IRQ_HANDLED;450}451 452static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)453{454 struct dsa_switch *ds = dev_id;455 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);456 457 priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &458 ~priv->irq1_mask;459 intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);460 461 if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF)) {462 priv->port_sts[7].link = true;463 dsa_port_phylink_mac_change(ds, 7, true);464 }465 if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF)) {466 priv->port_sts[7].link = false;467 dsa_port_phylink_mac_change(ds, 7, false);468 }469 470 return IRQ_HANDLED;471}472 473static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)474{475 unsigned int timeout = 1000;476 u32 reg;477 int ret;478 479 /* The watchdog reset does not work on 7278, we need to hit the480 * "external" reset line through the reset controller.481 */482 if (priv->type == BCM7278_DEVICE_ID) {483 ret = reset_control_assert(priv->rcdev);484 if (ret)485 return ret;486 487 return reset_control_deassert(priv->rcdev);488 }489 490 reg = core_readl(priv, CORE_WATCHDOG_CTRL);491 reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;492 core_writel(priv, reg, CORE_WATCHDOG_CTRL);493 494 do {495 reg = core_readl(priv, CORE_WATCHDOG_CTRL);496 if (!(reg & SOFTWARE_RESET))497 break;498 499 usleep_range(1000, 2000);500 } while (timeout-- > 0);501 502 if (timeout == 0)503 return -ETIMEDOUT;504 505 return 0;506}507 508static void bcm_sf2_crossbar_setup(struct bcm_sf2_priv *priv)509{510 struct device *dev = priv->dev->ds->dev;511 int shift;512 u32 mask;513 u32 reg;514 int i;515 516 mask = BIT(priv->num_crossbar_int_ports) - 1;517 518 reg = reg_readl(priv, REG_CROSSBAR);519 switch (priv->type) {520 case BCM4908_DEVICE_ID:521 shift = CROSSBAR_BCM4908_INT_P7 * priv->num_crossbar_int_ports;522 reg &= ~(mask << shift);523 if (0) /* FIXME */524 reg |= CROSSBAR_BCM4908_EXT_SERDES << shift;525 else if (priv->int_phy_mask & BIT(7))526 reg |= CROSSBAR_BCM4908_EXT_GPHY4 << shift;527 else if (phy_interface_mode_is_rgmii(priv->port_sts[7].mode))528 reg |= CROSSBAR_BCM4908_EXT_RGMII << shift;529 else if (WARN(1, "Invalid port mode\n"))530 return;531 break;532 default:533 return;534 }535 reg_writel(priv, reg, REG_CROSSBAR);536 537 reg = reg_readl(priv, REG_CROSSBAR);538 for (i = 0; i < priv->num_crossbar_int_ports; i++) {539 shift = i * priv->num_crossbar_int_ports;540 541 dev_dbg(dev, "crossbar int port #%d - ext port #%d\n", i,542 (reg >> shift) & mask);543 }544}545 546static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)547{548 intrl2_0_mask_set(priv, 0xffffffff);549 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);550 intrl2_1_mask_set(priv, 0xffffffff);551 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);552}553 554static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,555 struct device_node *dn)556{557 struct device *dev = priv->dev->ds->dev;558 struct bcm_sf2_port_status *port_st;559 struct device_node *port;560 unsigned int port_num;561 struct property *prop;562 int err;563 564 priv->moca_port = -1;565 566 for_each_available_child_of_node(dn, port) {567 if (of_property_read_u32(port, "reg", &port_num))568 continue;569 570 if (port_num >= DSA_MAX_PORTS) {571 dev_err(dev, "Invalid port number %d\n", port_num);572 continue;573 }574 575 port_st = &priv->port_sts[port_num];576 577 /* Internal PHYs get assigned a specific 'phy-mode' property578 * value: "internal" to help flag them before MDIO probing579 * has completed, since they might be turned off at that580 * time581 */582 err = of_get_phy_mode(port, &port_st->mode);583 if (err)584 continue;585 586 if (port_st->mode == PHY_INTERFACE_MODE_INTERNAL)587 priv->int_phy_mask |= 1 << port_num;588 589 if (port_st->mode == PHY_INTERFACE_MODE_MOCA)590 priv->moca_port = port_num;591 592 if (of_property_read_bool(port, "brcm,use-bcm-hdr"))593 priv->brcm_tag_mask |= 1 << port_num;594 595 /* Ensure that port 5 is not picked up as a DSA CPU port596 * flavour but a regular port instead. We should be using597 * devlink to be able to set the port flavour.598 */599 if (port_num == 5 && priv->type == BCM7278_DEVICE_ID) {600 prop = of_find_property(port, "ethernet", NULL);601 if (prop)602 of_remove_property(port, prop);603 }604 }605}606 607static int bcm_sf2_mdio_register(struct dsa_switch *ds)608{609 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);610 struct device_node *dn, *child;611 struct phy_device *phydev;612 struct property *prop;613 static int index;614 int err, reg;615 616 /* Find our integrated MDIO bus node */617 dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");618 priv->master_mii_bus = of_mdio_find_bus(dn);619 if (!priv->master_mii_bus) {620 err = -EPROBE_DEFER;621 goto err_of_node_put;622 }623 624 priv->user_mii_bus = mdiobus_alloc();625 if (!priv->user_mii_bus) {626 err = -ENOMEM;627 goto err_put_master_mii_bus_dev;628 }629 630 priv->user_mii_bus->priv = priv;631 priv->user_mii_bus->name = "sf2 user mii";632 priv->user_mii_bus->read = bcm_sf2_sw_mdio_read;633 priv->user_mii_bus->write = bcm_sf2_sw_mdio_write;634 snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",635 index++);636 637 /* Include the pseudo-PHY address to divert reads towards our638 * workaround. This is only required for 7445D0, since 7445E0639 * disconnects the internal switch pseudo-PHY such that we can use the640 * regular SWITCH_MDIO master controller instead.641 *642 * Here we flag the pseudo PHY as needing special treatment and would643 * otherwise make all other PHY read/writes go to the master MDIO bus644 * controller that comes with this switch backed by the "mdio-unimac"645 * driver.646 */647 if (of_machine_is_compatible("brcm,bcm7445d0"))648 priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR) | (1 << 0);649 else650 priv->indir_phy_mask = 0;651 652 ds->phys_mii_mask = priv->indir_phy_mask;653 ds->user_mii_bus = priv->user_mii_bus;654 priv->user_mii_bus->parent = ds->dev->parent;655 priv->user_mii_bus->phy_mask = ~priv->indir_phy_mask;656 657 /* We need to make sure that of_phy_connect() will not work by658 * removing the 'phandle' and 'linux,phandle' properties and659 * unregister the existing PHY device that was already registered.660 */661 for_each_available_child_of_node(dn, child) {662 if (of_property_read_u32(child, "reg", ®) ||663 reg >= PHY_MAX_ADDR)664 continue;665 666 if (!(priv->indir_phy_mask & BIT(reg)))667 continue;668 669 prop = of_find_property(child, "phandle", NULL);670 if (prop)671 of_remove_property(child, prop);672 673 prop = of_find_property(child, "linux,phandle", NULL);674 if (prop)675 of_remove_property(child, prop);676 677 phydev = of_phy_find_device(child);678 if (phydev) {679 phy_device_remove(phydev);680 phy_device_free(phydev);681 }682 }683 684 err = mdiobus_register(priv->user_mii_bus);685 if (err)686 goto err_free_user_mii_bus;687 688 of_node_put(dn);689 690 return 0;691 692err_free_user_mii_bus:693 mdiobus_free(priv->user_mii_bus);694err_put_master_mii_bus_dev:695 put_device(&priv->master_mii_bus->dev);696err_of_node_put:697 of_node_put(dn);698 return err;699}700 701static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)702{703 mdiobus_unregister(priv->user_mii_bus);704 mdiobus_free(priv->user_mii_bus);705 put_device(&priv->master_mii_bus->dev);706}707 708static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)709{710 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);711 712 /* The BCM7xxx PHY driver expects to find the integrated PHY revision713 * in bits 15:8 and the patch level in bits 7:0 which is exactly what714 * the REG_PHY_REVISION register layout is.715 */716 if (priv->int_phy_mask & BIT(port))717 return priv->hw_params.gphy_rev;718 else719 return PHY_BRCM_AUTO_PWRDWN_ENABLE |720 PHY_BRCM_DIS_TXCRXC_NOENRGY |721 PHY_BRCM_IDDQ_SUSPEND;722}723 724static void bcm_sf2_sw_get_caps(struct dsa_switch *ds, int port,725 struct phylink_config *config)726{727 unsigned long *interfaces = config->supported_interfaces;728 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);729 730 if (priv->int_phy_mask & BIT(port)) {731 __set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);732 } else if (priv->moca_port == port) {733 __set_bit(PHY_INTERFACE_MODE_MOCA, interfaces);734 } else {735 __set_bit(PHY_INTERFACE_MODE_MII, interfaces);736 __set_bit(PHY_INTERFACE_MODE_REVMII, interfaces);737 __set_bit(PHY_INTERFACE_MODE_GMII, interfaces);738 phy_interface_set_rgmii(interfaces);739 }740 741 config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |742 MAC_10 | MAC_100 | MAC_1000;743}744 745static void bcm_sf2_sw_mac_config(struct phylink_config *config,746 unsigned int mode,747 const struct phylink_link_state *state)748{749 struct dsa_port *dp = dsa_phylink_to_port(config);750 u32 id_mode_dis = 0, port_mode;751 struct bcm_sf2_priv *priv;752 u32 reg_rgmii_ctrl;753 u32 reg;754 755 priv = bcm_sf2_to_priv(dp->ds);756 757 if (dp->index == core_readl(priv, CORE_IMP0_PRT_ID))758 return;759 760 switch (state->interface) {761 case PHY_INTERFACE_MODE_RGMII:762 id_mode_dis = 1;763 fallthrough;764 case PHY_INTERFACE_MODE_RGMII_TXID:765 port_mode = EXT_GPHY;766 break;767 case PHY_INTERFACE_MODE_MII:768 port_mode = EXT_EPHY;769 break;770 case PHY_INTERFACE_MODE_REVMII:771 port_mode = EXT_REVMII;772 break;773 default:774 /* Nothing required for all other PHYs: internal and MoCA */775 return;776 }777 778 reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, dp->index);779 780 /* Clear id_mode_dis bit, and the existing port mode, let781 * RGMII_MODE_EN bet set by mac_link_{up,down}782 */783 reg = reg_readl(priv, reg_rgmii_ctrl);784 reg &= ~ID_MODE_DIS;785 reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);786 787 reg |= port_mode;788 if (id_mode_dis)789 reg |= ID_MODE_DIS;790 791 reg_writel(priv, reg, reg_rgmii_ctrl);792}793 794static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port,795 phy_interface_t interface, bool link)796{797 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);798 u32 reg_rgmii_ctrl;799 u32 reg;800 801 if (!phy_interface_mode_is_rgmii(interface) &&802 interface != PHY_INTERFACE_MODE_MII &&803 interface != PHY_INTERFACE_MODE_REVMII)804 return;805 806 reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);807 808 /* If the link is down, just disable the interface to conserve power */809 reg = reg_readl(priv, reg_rgmii_ctrl);810 if (link)811 reg |= RGMII_MODE_EN;812 else813 reg &= ~RGMII_MODE_EN;814 reg_writel(priv, reg, reg_rgmii_ctrl);815}816 817static void bcm_sf2_sw_mac_link_down(struct phylink_config *config,818 unsigned int mode,819 phy_interface_t interface)820{821 struct dsa_port *dp = dsa_phylink_to_port(config);822 struct bcm_sf2_priv *priv;823 int port = dp->index;824 u32 reg, offset;825 826 priv = bcm_sf2_to_priv(dp->ds);827 if (priv->wol_ports_mask & BIT(port))828 return;829 830 offset = bcm_sf2_port_override_offset(priv, port);831 reg = core_readl(priv, offset);832 reg &= ~LINK_STS;833 core_writel(priv, reg, offset);834 835 bcm_sf2_sw_mac_link_set(dp->ds, port, interface, false);836}837 838static void bcm_sf2_sw_mac_link_up(struct phylink_config *config,839 struct phy_device *phydev,840 unsigned int mode,841 phy_interface_t interface,842 int speed, int duplex,843 bool tx_pause, bool rx_pause)844{845 struct dsa_port *dp = dsa_phylink_to_port(config);846 struct bcm_sf2_priv *priv;847 u32 reg_rgmii_ctrl = 0;848 struct ethtool_keee *p;849 int port = dp->index;850 u32 reg, offset;851 852 bcm_sf2_sw_mac_link_set(dp->ds, port, interface, true);853 854 priv = bcm_sf2_to_priv(dp->ds);855 offset = bcm_sf2_port_override_offset(priv, port);856 857 if (phy_interface_mode_is_rgmii(interface) ||858 interface == PHY_INTERFACE_MODE_MII ||859 interface == PHY_INTERFACE_MODE_REVMII) {860 reg_rgmii_ctrl = bcm_sf2_reg_rgmii_cntrl(priv, port);861 reg = reg_readl(priv, reg_rgmii_ctrl);862 reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);863 864 if (tx_pause)865 reg |= TX_PAUSE_EN;866 if (rx_pause)867 reg |= RX_PAUSE_EN;868 869 reg_writel(priv, reg, reg_rgmii_ctrl);870 }871 872 reg = LINK_STS;873 if (port == 8) {874 if (priv->type == BCM4908_DEVICE_ID)875 reg |= GMII_SPEED_UP_2G;876 reg |= MII_SW_OR;877 } else {878 reg |= SW_OVERRIDE;879 }880 881 switch (speed) {882 case SPEED_1000:883 reg |= SPDSTS_1000 << SPEED_SHIFT;884 break;885 case SPEED_100:886 reg |= SPDSTS_100 << SPEED_SHIFT;887 break;888 }889 890 if (duplex == DUPLEX_FULL)891 reg |= DUPLX_MODE;892 893 if (tx_pause)894 reg |= TXFLOW_CNTL;895 if (rx_pause)896 reg |= RXFLOW_CNTL;897 898 core_writel(priv, reg, offset);899 900 if (mode == MLO_AN_PHY && phydev) {901 p = &priv->dev->ports[port].eee;902 p->eee_enabled = b53_eee_init(dp->ds, port, phydev);903 }904}905 906static void bcm_sf2_sw_fixed_state(struct dsa_switch *ds, int port,907 struct phylink_link_state *status)908{909 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);910 911 status->link = false;912 913 /* MoCA port is special as we do not get link status from CORE_LNKSTS,914 * which means that we need to force the link at the port override915 * level to get the data to flow. We do use what the interrupt handler916 * did determine before.917 *918 * For the other ports, we just force the link status, since this is919 * a fixed PHY device.920 */921 if (port == priv->moca_port) {922 status->link = priv->port_sts[port].link;923 /* For MoCA interfaces, also force a link down notification924 * since some version of the user-space daemon (mocad) use925 * cmd->autoneg to force the link, which messes up the PHY926 * state machine and make it go in PHY_FORCING state instead.927 */928 if (!status->link)929 netif_carrier_off(dsa_to_port(ds, port)->user);930 status->duplex = DUPLEX_FULL;931 } else {932 status->link = true;933 }934}935 936static void bcm_sf2_enable_acb(struct dsa_switch *ds)937{938 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);939 u32 reg;940 941 /* Enable ACB globally */942 reg = acb_readl(priv, ACB_CONTROL);943 reg |= (ACB_FLUSH_MASK << ACB_FLUSH_SHIFT);944 acb_writel(priv, reg, ACB_CONTROL);945 reg &= ~(ACB_FLUSH_MASK << ACB_FLUSH_SHIFT);946 reg |= ACB_EN | ACB_ALGORITHM;947 acb_writel(priv, reg, ACB_CONTROL);948}949 950static int bcm_sf2_sw_suspend(struct dsa_switch *ds)951{952 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);953 unsigned int port;954 955 bcm_sf2_intr_disable(priv);956 957 /* Disable all ports physically present including the IMP958 * port, the other ones have already been disabled during959 * bcm_sf2_sw_setup960 */961 for (port = 0; port < ds->num_ports; port++) {962 if (dsa_is_user_port(ds, port) || dsa_is_cpu_port(ds, port))963 bcm_sf2_port_disable(ds, port);964 }965 966 if (!priv->wol_ports_mask)967 clk_disable_unprepare(priv->clk);968 969 return 0;970}971 972static int bcm_sf2_sw_resume(struct dsa_switch *ds)973{974 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);975 int ret;976 977 if (!priv->wol_ports_mask)978 clk_prepare_enable(priv->clk);979 980 ret = bcm_sf2_sw_rst(priv);981 if (ret) {982 pr_err("%s: failed to software reset switch\n", __func__);983 return ret;984 }985 986 bcm_sf2_crossbar_setup(priv);987 988 ret = bcm_sf2_cfp_resume(ds);989 if (ret)990 return ret;991 992 if (priv->hw_params.num_gphy == 1)993 bcm_sf2_gphy_enable_set(ds, true);994 995 ds->ops->setup(ds);996 997 return 0;998}999 1000static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port,1001 struct ethtool_wolinfo *wol)1002{1003 struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port));1004 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);1005 struct ethtool_wolinfo pwol = { };1006 1007 /* Get the parent device WoL settings */1008 if (p->ethtool_ops->get_wol)1009 p->ethtool_ops->get_wol(p, &pwol);1010 1011 /* Advertise the parent device supported settings */1012 wol->supported = pwol.supported;1013 memset(&wol->sopass, 0, sizeof(wol->sopass));1014 1015 if (pwol.wolopts & WAKE_MAGICSECURE)1016 memcpy(&wol->sopass, pwol.sopass, sizeof(wol->sopass));1017 1018 if (priv->wol_ports_mask & (1 << port))1019 wol->wolopts = pwol.wolopts;1020 else1021 wol->wolopts = 0;1022}1023 1024static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port,1025 struct ethtool_wolinfo *wol)1026{1027 struct net_device *p = dsa_port_to_conduit(dsa_to_port(ds, port));1028 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);1029 s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;1030 struct ethtool_wolinfo pwol = { };1031 1032 if (p->ethtool_ops->get_wol)1033 p->ethtool_ops->get_wol(p, &pwol);1034 if (wol->wolopts & ~pwol.supported)1035 return -EINVAL;1036 1037 if (wol->wolopts)1038 priv->wol_ports_mask |= (1 << port);1039 else1040 priv->wol_ports_mask &= ~(1 << port);1041 1042 /* If we have at least one port enabled, make sure the CPU port1043 * is also enabled. If the CPU port is the last one enabled, we disable1044 * it since this configuration does not make sense.1045 */1046 if (priv->wol_ports_mask && priv->wol_ports_mask != (1 << cpu_port))1047 priv->wol_ports_mask |= (1 << cpu_port);1048 else1049 priv->wol_ports_mask &= ~(1 << cpu_port);1050 1051 return p->ethtool_ops->set_wol(p, wol);1052}1053 1054static int bcm_sf2_sw_setup(struct dsa_switch *ds)1055{1056 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);1057 unsigned int port;1058 1059 /* Enable all valid ports and disable those unused */1060 for (port = 0; port < priv->hw_params.num_ports; port++) {1061 /* IMP port receives special treatment */1062 if (dsa_is_user_port(ds, port))1063 bcm_sf2_port_setup(ds, port, NULL);1064 else if (dsa_is_cpu_port(ds, port))1065 bcm_sf2_imp_setup(ds, port);1066 else1067 bcm_sf2_port_disable(ds, port);1068 }1069 1070 b53_configure_vlan(ds);1071 bcm_sf2_enable_acb(ds);1072 1073 return b53_setup_devlink_resources(ds);1074}1075 1076static void bcm_sf2_sw_teardown(struct dsa_switch *ds)1077{1078 dsa_devlink_resources_unregister(ds);1079}1080 1081/* The SWITCH_CORE register space is managed by b53 but operates on a page +1082 * register basis so we need to translate that into an address that the1083 * bus-glue understands.1084 */1085#define SF2_PAGE_REG_MKADDR(page, reg) ((page) << 10 | (reg) << 2)1086 1087static int bcm_sf2_core_read8(struct b53_device *dev, u8 page, u8 reg,1088 u8 *val)1089{1090 struct bcm_sf2_priv *priv = dev->priv;1091 1092 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));1093 1094 return 0;1095}1096 1097static int bcm_sf2_core_read16(struct b53_device *dev, u8 page, u8 reg,1098 u16 *val)1099{1100 struct bcm_sf2_priv *priv = dev->priv;1101 1102 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));1103 1104 return 0;1105}1106 1107static int bcm_sf2_core_read32(struct b53_device *dev, u8 page, u8 reg,1108 u32 *val)1109{1110 struct bcm_sf2_priv *priv = dev->priv;1111 1112 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));1113 1114 return 0;1115}1116 1117static int bcm_sf2_core_read64(struct b53_device *dev, u8 page, u8 reg,1118 u64 *val)1119{1120 struct bcm_sf2_priv *priv = dev->priv;1121 1122 *val = core_readq(priv, SF2_PAGE_REG_MKADDR(page, reg));1123 1124 return 0;1125}1126 1127static int bcm_sf2_core_write8(struct b53_device *dev, u8 page, u8 reg,1128 u8 value)1129{1130 struct bcm_sf2_priv *priv = dev->priv;1131 1132 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));1133 1134 return 0;1135}1136 1137static int bcm_sf2_core_write16(struct b53_device *dev, u8 page, u8 reg,1138 u16 value)1139{1140 struct bcm_sf2_priv *priv = dev->priv;1141 1142 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));1143 1144 return 0;1145}1146 1147static int bcm_sf2_core_write32(struct b53_device *dev, u8 page, u8 reg,1148 u32 value)1149{1150 struct bcm_sf2_priv *priv = dev->priv;1151 1152 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));1153 1154 return 0;1155}1156 1157static int bcm_sf2_core_write64(struct b53_device *dev, u8 page, u8 reg,1158 u64 value)1159{1160 struct bcm_sf2_priv *priv = dev->priv;1161 1162 core_writeq(priv, value, SF2_PAGE_REG_MKADDR(page, reg));1163 1164 return 0;1165}1166 1167static const struct b53_io_ops bcm_sf2_io_ops = {1168 .read8 = bcm_sf2_core_read8,1169 .read16 = bcm_sf2_core_read16,1170 .read32 = bcm_sf2_core_read32,1171 .read48 = bcm_sf2_core_read64,1172 .read64 = bcm_sf2_core_read64,1173 .write8 = bcm_sf2_core_write8,1174 .write16 = bcm_sf2_core_write16,1175 .write32 = bcm_sf2_core_write32,1176 .write48 = bcm_sf2_core_write64,1177 .write64 = bcm_sf2_core_write64,1178};1179 1180static void bcm_sf2_sw_get_strings(struct dsa_switch *ds, int port,1181 u32 stringset, uint8_t *data)1182{1183 int cnt = b53_get_sset_count(ds, port, stringset);1184 1185 b53_get_strings(ds, port, stringset, data);1186 bcm_sf2_cfp_get_strings(ds, port, stringset,1187 data + cnt * ETH_GSTRING_LEN);1188}1189 1190static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds, int port,1191 uint64_t *data)1192{1193 int cnt = b53_get_sset_count(ds, port, ETH_SS_STATS);1194 1195 b53_get_ethtool_stats(ds, port, data);1196 bcm_sf2_cfp_get_ethtool_stats(ds, port, data + cnt);1197}1198 1199static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds, int port,1200 int sset)1201{1202 int cnt = b53_get_sset_count(ds, port, sset);1203 1204 if (cnt < 0)1205 return cnt;1206 1207 cnt += bcm_sf2_cfp_get_sset_count(ds, port, sset);1208 1209 return cnt;1210}1211 1212static const struct phylink_mac_ops bcm_sf2_phylink_mac_ops = {1213 .mac_config = bcm_sf2_sw_mac_config,1214 .mac_link_down = bcm_sf2_sw_mac_link_down,1215 .mac_link_up = bcm_sf2_sw_mac_link_up,1216};1217 1218static const struct dsa_switch_ops bcm_sf2_ops = {1219 .get_tag_protocol = b53_get_tag_protocol,1220 .setup = bcm_sf2_sw_setup,1221 .teardown = bcm_sf2_sw_teardown,1222 .get_strings = bcm_sf2_sw_get_strings,1223 .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats,1224 .get_sset_count = bcm_sf2_sw_get_sset_count,1225 .get_ethtool_phy_stats = b53_get_ethtool_phy_stats,1226 .get_phy_flags = bcm_sf2_sw_get_phy_flags,1227 .phylink_get_caps = bcm_sf2_sw_get_caps,1228 .phylink_fixed_state = bcm_sf2_sw_fixed_state,1229 .suspend = bcm_sf2_sw_suspend,1230 .resume = bcm_sf2_sw_resume,1231 .get_wol = bcm_sf2_sw_get_wol,1232 .set_wol = bcm_sf2_sw_set_wol,1233 .port_enable = bcm_sf2_port_setup,1234 .port_disable = bcm_sf2_port_disable,1235 .get_mac_eee = b53_get_mac_eee,1236 .set_mac_eee = b53_set_mac_eee,1237 .port_bridge_join = b53_br_join,1238 .port_bridge_leave = b53_br_leave,1239 .port_pre_bridge_flags = b53_br_flags_pre,1240 .port_bridge_flags = b53_br_flags,1241 .port_stp_state_set = b53_br_set_stp_state,1242 .port_fast_age = b53_br_fast_age,1243 .port_vlan_filtering = b53_vlan_filtering,1244 .port_vlan_add = b53_vlan_add,1245 .port_vlan_del = b53_vlan_del,1246 .port_fdb_dump = b53_fdb_dump,1247 .port_fdb_add = b53_fdb_add,1248 .port_fdb_del = b53_fdb_del,1249 .get_rxnfc = bcm_sf2_get_rxnfc,1250 .set_rxnfc = bcm_sf2_set_rxnfc,1251 .port_mirror_add = b53_mirror_add,1252 .port_mirror_del = b53_mirror_del,1253 .port_mdb_add = b53_mdb_add,1254 .port_mdb_del = b53_mdb_del,1255};1256 1257struct bcm_sf2_of_data {1258 u32 type;1259 const u16 *reg_offsets;1260 unsigned int core_reg_align;1261 unsigned int num_cfp_rules;1262 unsigned int num_crossbar_int_ports;1263};1264 1265static const u16 bcm_sf2_4908_reg_offsets[] = {1266 [REG_SWITCH_CNTRL] = 0x00,1267 [REG_SWITCH_STATUS] = 0x04,1268 [REG_DIR_DATA_WRITE] = 0x08,1269 [REG_DIR_DATA_READ] = 0x0c,1270 [REG_SWITCH_REVISION] = 0x10,1271 [REG_PHY_REVISION] = 0x14,1272 [REG_SPHY_CNTRL] = 0x24,1273 [REG_CROSSBAR] = 0xc8,1274 [REG_RGMII_11_CNTRL] = 0x014c,1275 [REG_LED_0_CNTRL] = 0x40,1276 [REG_LED_1_CNTRL] = 0x4c,1277 [REG_LED_2_CNTRL] = 0x58,1278 [REG_LED_3_CNTRL] = 0x64,1279 [REG_LED_4_CNTRL] = 0x88,1280 [REG_LED_5_CNTRL] = 0xa0,1281 [REG_LED_AGGREGATE_CTRL] = 0xb8,1282 1283};1284 1285static const struct bcm_sf2_of_data bcm_sf2_4908_data = {1286 .type = BCM4908_DEVICE_ID,1287 .core_reg_align = 0,1288 .reg_offsets = bcm_sf2_4908_reg_offsets,1289 .num_cfp_rules = 256,1290 .num_crossbar_int_ports = 2,1291};1292 1293/* Register offsets for the SWITCH_REG_* block */1294static const u16 bcm_sf2_7445_reg_offsets[] = {1295 [REG_SWITCH_CNTRL] = 0x00,1296 [REG_SWITCH_STATUS] = 0x04,1297 [REG_DIR_DATA_WRITE] = 0x08,1298 [REG_DIR_DATA_READ] = 0x0C,1299 [REG_SWITCH_REVISION] = 0x18,1300 [REG_PHY_REVISION] = 0x1C,1301 [REG_SPHY_CNTRL] = 0x2C,1302 [REG_RGMII_0_CNTRL] = 0x34,1303 [REG_RGMII_1_CNTRL] = 0x40,1304 [REG_RGMII_2_CNTRL] = 0x4c,1305 [REG_LED_0_CNTRL] = 0x90,1306 [REG_LED_1_CNTRL] = 0x94,1307 [REG_LED_2_CNTRL] = 0x98,1308};1309 1310static const struct bcm_sf2_of_data bcm_sf2_7445_data = {1311 .type = BCM7445_DEVICE_ID,1312 .core_reg_align = 0,1313 .reg_offsets = bcm_sf2_7445_reg_offsets,1314 .num_cfp_rules = 256,1315};1316 1317static const u16 bcm_sf2_7278_reg_offsets[] = {1318 [REG_SWITCH_CNTRL] = 0x00,1319 [REG_SWITCH_STATUS] = 0x04,1320 [REG_DIR_DATA_WRITE] = 0x08,1321 [REG_DIR_DATA_READ] = 0x0c,1322 [REG_SWITCH_REVISION] = 0x10,1323 [REG_PHY_REVISION] = 0x14,1324 [REG_SPHY_CNTRL] = 0x24,1325 [REG_RGMII_0_CNTRL] = 0xe0,1326 [REG_RGMII_1_CNTRL] = 0xec,1327 [REG_RGMII_2_CNTRL] = 0xf8,1328 [REG_LED_0_CNTRL] = 0x40,1329 [REG_LED_1_CNTRL] = 0x4c,1330 [REG_LED_2_CNTRL] = 0x58,1331};1332 1333static const struct bcm_sf2_of_data bcm_sf2_7278_data = {1334 .type = BCM7278_DEVICE_ID,1335 .core_reg_align = 1,1336 .reg_offsets = bcm_sf2_7278_reg_offsets,1337 .num_cfp_rules = 128,1338};1339 1340static const struct of_device_id bcm_sf2_of_match[] = {1341 { .compatible = "brcm,bcm4908-switch",1342 .data = &bcm_sf2_4908_data1343 },1344 { .compatible = "brcm,bcm7445-switch-v4.0",1345 .data = &bcm_sf2_7445_data1346 },1347 { .compatible = "brcm,bcm7278-switch-v4.0",1348 .data = &bcm_sf2_7278_data1349 },1350 { .compatible = "brcm,bcm7278-switch-v4.8",1351 .data = &bcm_sf2_7278_data1352 },1353 { /* sentinel */ },1354};1355MODULE_DEVICE_TABLE(of, bcm_sf2_of_match);1356 1357static int bcm_sf2_sw_probe(struct platform_device *pdev)1358{1359 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;1360 struct device_node *dn = pdev->dev.of_node;1361 const struct of_device_id *of_id = NULL;1362 const struct bcm_sf2_of_data *data;1363 struct b53_platform_data *pdata;1364 struct dsa_switch_ops *ops;1365 struct device_node *ports;1366 struct bcm_sf2_priv *priv;1367 struct b53_device *dev;1368 struct dsa_switch *ds;1369 void __iomem **base;1370 unsigned int i;1371 u32 reg, rev;1372 int ret;1373 1374 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);1375 if (!priv)1376 return -ENOMEM;1377 1378 ops = devm_kzalloc(&pdev->dev, sizeof(*ops), GFP_KERNEL);1379 if (!ops)1380 return -ENOMEM;1381 1382 dev = b53_switch_alloc(&pdev->dev, &bcm_sf2_io_ops, priv);1383 if (!dev)1384 return -ENOMEM;1385 1386 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);1387 if (!pdata)1388 return -ENOMEM;1389 1390 of_id = of_match_node(bcm_sf2_of_match, dn);1391 if (!of_id || !of_id->data)1392 return -EINVAL;1393 1394 data = of_id->data;1395 1396 /* Set SWITCH_REG register offsets and SWITCH_CORE align factor */1397 priv->type = data->type;1398 priv->reg_offsets = data->reg_offsets;1399 priv->core_reg_align = data->core_reg_align;1400 priv->num_cfp_rules = data->num_cfp_rules;1401 priv->num_crossbar_int_ports = data->num_crossbar_int_ports;1402 1403 priv->rcdev = devm_reset_control_get_optional_exclusive(&pdev->dev,1404 "switch");1405 if (IS_ERR(priv->rcdev))1406 return PTR_ERR(priv->rcdev);1407 1408 /* Auto-detection using standard registers will not work, so1409 * provide an indication of what kind of device we are for1410 * b53_common to work with1411 */1412 pdata->chip_id = priv->type;1413 dev->pdata = pdata;1414 1415 priv->dev = dev;1416 ds = dev->ds;1417 ds->ops = &bcm_sf2_ops;1418 ds->phylink_mac_ops = &bcm_sf2_phylink_mac_ops;1419 1420 /* Advertise the 8 egress queues */1421 ds->num_tx_queues = SF2_NUM_EGRESS_QUEUES;1422 1423 dev_set_drvdata(&pdev->dev, priv);1424 1425 spin_lock_init(&priv->indir_lock);1426 mutex_init(&priv->cfp.lock);1427 INIT_LIST_HEAD(&priv->cfp.rules_list);1428 1429 /* CFP rule #0 cannot be used for specific classifications, flag it as1430 * permanently used1431 */1432 set_bit(0, priv->cfp.used);1433 set_bit(0, priv->cfp.unique);1434 1435 /* Balance of_node_put() done by of_find_node_by_name() */1436 of_node_get(dn);1437 ports = of_find_node_by_name(dn, "ports");1438 if (ports) {1439 bcm_sf2_identify_ports(priv, ports);1440 of_node_put(ports);1441 }1442 1443 priv->irq0 = irq_of_parse_and_map(dn, 0);1444 priv->irq1 = irq_of_parse_and_map(dn, 1);1445 1446 base = &priv->core;1447 for (i = 0; i < BCM_SF2_REGS_NUM; i++) {1448 *base = devm_platform_ioremap_resource(pdev, i);1449 if (IS_ERR(*base)) {1450 pr_err("unable to find register: %s\n", reg_names[i]);1451 return PTR_ERR(*base);1452 }1453 base++;1454 }1455 1456 priv->clk = devm_clk_get_optional(&pdev->dev, "sw_switch");1457 if (IS_ERR(priv->clk))1458 return PTR_ERR(priv->clk);1459 1460 ret = clk_prepare_enable(priv->clk);1461 if (ret)1462 return ret;1463 1464 priv->clk_mdiv = devm_clk_get_optional(&pdev->dev, "sw_switch_mdiv");1465 if (IS_ERR(priv->clk_mdiv)) {1466 ret = PTR_ERR(priv->clk_mdiv);1467 goto out_clk;1468 }1469 1470 ret = clk_prepare_enable(priv->clk_mdiv);1471 if (ret)1472 goto out_clk;1473 1474 ret = bcm_sf2_sw_rst(priv);1475 if (ret) {1476 pr_err("unable to software reset switch: %d\n", ret);1477 goto out_clk_mdiv;1478 }1479 1480 bcm_sf2_crossbar_setup(priv);1481 1482 bcm_sf2_gphy_enable_set(priv->dev->ds, true);1483 1484 ret = bcm_sf2_mdio_register(ds);1485 if (ret) {1486 pr_err("failed to register MDIO bus\n");1487 goto out_clk_mdiv;1488 }1489 1490 bcm_sf2_gphy_enable_set(priv->dev->ds, false);1491 1492 ret = bcm_sf2_cfp_rst(priv);1493 if (ret) {1494 pr_err("failed to reset CFP\n");1495 goto out_mdio;1496 }1497 1498 /* Disable all interrupts and request them */1499 bcm_sf2_intr_disable(priv);1500 1501 ret = devm_request_irq(&pdev->dev, priv->irq0, bcm_sf2_switch_0_isr, 0,1502 "switch_0", ds);1503 if (ret < 0) {1504 pr_err("failed to request switch_0 IRQ\n");1505 goto out_mdio;1506 }1507 1508 ret = devm_request_irq(&pdev->dev, priv->irq1, bcm_sf2_switch_1_isr, 0,1509 "switch_1", ds);1510 if (ret < 0) {1511 pr_err("failed to request switch_1 IRQ\n");1512 goto out_mdio;1513 }1514 1515 /* Reset the MIB counters */1516 reg = core_readl(priv, CORE_GMNCFGCFG);1517 reg |= RST_MIB_CNT;1518 core_writel(priv, reg, CORE_GMNCFGCFG);1519 reg &= ~RST_MIB_CNT;1520 core_writel(priv, reg, CORE_GMNCFGCFG);1521 1522 /* Get the maximum number of ports for this switch */1523 priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;1524 if (priv->hw_params.num_ports > DSA_MAX_PORTS)1525 priv->hw_params.num_ports = DSA_MAX_PORTS;1526 1527 /* Assume a single GPHY setup if we can't read that property */1528 if (of_property_read_u32(dn, "brcm,num-gphy",1529 &priv->hw_params.num_gphy))1530 priv->hw_params.num_gphy = 1;1531 1532 rev = reg_readl(priv, REG_SWITCH_REVISION);1533 priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &1534 SWITCH_TOP_REV_MASK;1535 priv->hw_params.core_rev = (rev & SF2_REV_MASK);1536 1537 rev = reg_readl(priv, REG_PHY_REVISION);1538 priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;1539 1540 ret = b53_switch_register(dev);1541 if (ret)1542 goto out_mdio;1543 1544 dev_info(&pdev->dev,1545 "Starfighter 2 top: %x.%02x, core: %x.%02x, IRQs: %d, %d\n",1546 priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,1547 priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,1548 priv->irq0, priv->irq1);1549 1550 return 0;1551 1552out_mdio:1553 bcm_sf2_mdio_unregister(priv);1554out_clk_mdiv:1555 clk_disable_unprepare(priv->clk_mdiv);1556out_clk:1557 clk_disable_unprepare(priv->clk);1558 return ret;1559}1560 1561static void bcm_sf2_sw_remove(struct platform_device *pdev)1562{1563 struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);1564 1565 if (!priv)1566 return;1567 1568 priv->wol_ports_mask = 0;1569 /* Disable interrupts */1570 bcm_sf2_intr_disable(priv);1571 dsa_unregister_switch(priv->dev->ds);1572 bcm_sf2_cfp_exit(priv->dev->ds);1573 bcm_sf2_mdio_unregister(priv);1574 clk_disable_unprepare(priv->clk_mdiv);1575 clk_disable_unprepare(priv->clk);1576 if (priv->type == BCM7278_DEVICE_ID)1577 reset_control_assert(priv->rcdev);1578}1579 1580static void bcm_sf2_sw_shutdown(struct platform_device *pdev)1581{1582 struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);1583 1584 if (!priv)1585 return;1586 1587 /* For a kernel about to be kexec'd we want to keep the GPHY on for a1588 * successful MDIO bus scan to occur. If we did turn off the GPHY1589 * before (e.g: port_disable), this will also power it back on.1590 *1591 * Do not rely on kexec_in_progress, just power the PHY on.1592 */1593 if (priv->hw_params.num_gphy == 1)1594 bcm_sf2_gphy_enable_set(priv->dev->ds, true);1595 1596 dsa_switch_shutdown(priv->dev->ds);1597 1598 platform_set_drvdata(pdev, NULL);1599}1600 1601#ifdef CONFIG_PM_SLEEP1602static int bcm_sf2_suspend(struct device *dev)1603{1604 struct bcm_sf2_priv *priv = dev_get_drvdata(dev);1605 1606 return dsa_switch_suspend(priv->dev->ds);1607}1608 1609static int bcm_sf2_resume(struct device *dev)1610{1611 struct bcm_sf2_priv *priv = dev_get_drvdata(dev);1612 1613 return dsa_switch_resume(priv->dev->ds);1614}1615#endif /* CONFIG_PM_SLEEP */1616 1617static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,1618 bcm_sf2_suspend, bcm_sf2_resume);1619 1620 1621static struct platform_driver bcm_sf2_driver = {1622 .probe = bcm_sf2_sw_probe,1623 .remove_new = bcm_sf2_sw_remove,1624 .shutdown = bcm_sf2_sw_shutdown,1625 .driver = {1626 .name = "brcm-sf2",1627 .of_match_table = bcm_sf2_of_match,1628 .pm = &bcm_sf2_pm_ops,1629 },1630};1631module_platform_driver(bcm_sf2_driver);1632 1633MODULE_AUTHOR("Broadcom Corporation");1634MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");1635MODULE_LICENSE("GPL");1636MODULE_ALIAS("platform:brcm-sf2");1637