--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.h +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h @@ -336,6 +336,9 @@ struct bcm_enet_priv { struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT]; int sw_port_link[ENETSW_MAX_PORT]; + /* platform device for associated switch */ + struct platform_device *b53_device; + /* used to poll switch port state */ struct timer_list swphy_poll; spinlock_t enetsw_mdio_lock; --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "bcm63xx_enet.h" @@ -1975,7 +1976,8 @@ static int bcm_enet_remove(struct platfo return 0; } -struct platform_driver bcm63xx_enet_driver = { + +static struct platform_driver bcm63xx_enet_driver = { .probe = bcm_enet_probe, .remove = bcm_enet_remove, .driver = { @@ -1984,6 +1986,42 @@ struct platform_driver bcm63xx_enet_driv }, }; +struct b53_platform_data bcm63xx_b53_pdata = { + .chip_id = 0x6300, + .big_endian = 1, +}; + +struct platform_device bcm63xx_b53_dev = { + .name = "b53-switch", + .id = -1, + .dev = { + .platform_data = &bcm63xx_b53_pdata, + }, +}; + +static int bcmenet_switch_register(struct bcm_enet_priv *priv, u16 port_mask) +{ + int ret; + + bcm63xx_b53_pdata.regs = priv->base; + bcm63xx_b53_pdata.enabled_ports = port_mask; + bcm63xx_b53_pdata.alias = priv->net_dev->name; + + ret = platform_device_register(&bcm63xx_b53_dev); + if (!ret) + priv->b53_device = &bcm63xx_b53_dev; + + return ret; +} + +static void bcmenet_switch_unregister(struct bcm_enet_priv *priv) +{ + if (priv->b53_device) + platform_device_unregister(&bcm63xx_b53_dev); + + priv->b53_device = NULL; +} + /* * switch mii access callbacks */ @@ -2237,29 +2275,6 @@ static int bcm_enetsw_open(struct net_de enetsw_writeb(priv, rgmii_ctrl, ENETSW_RGMII_CTRL_REG(i)); } - /* reset mib */ - val = enetsw_readb(priv, ENETSW_GMCR_REG); - val |= ENETSW_GMCR_RST_MIB_MASK; - enetsw_writeb(priv, val, ENETSW_GMCR_REG); - mdelay(1); - val &= ~ENETSW_GMCR_RST_MIB_MASK; - enetsw_writeb(priv, val, ENETSW_GMCR_REG); - mdelay(1); - - /* force CPU port state */ - val = enetsw_readb(priv, ENETSW_IMPOV_REG); - val |= ENETSW_IMPOV_FORCE_MASK | ENETSW_IMPOV_LINKUP_MASK; - enetsw_writeb(priv, val, ENETSW_IMPOV_REG); - - /* enable switch forward engine */ - val = enetsw_readb(priv, ENETSW_SWMODE_REG); - val |= ENETSW_SWMODE_FWD_EN_MASK; - enetsw_writeb(priv, val, ENETSW_SWMODE_REG); - - /* enable jumbo on all ports */ - enetsw_writel(priv, 0x1ff, ENETSW_JMBCTL_PORT_REG); - enetsw_writew(priv, 9728, ENETSW_JMBCTL_MAXSIZE_REG); - /* initialize flow control buffer allocation */ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0, ENETDMA_BUFALLOC_REG(priv->rx_chan)); @@ -2719,6 +2734,9 @@ static int bcm_enetsw_probe(struct platf struct bcm63xx_enetsw_platform_data *pd; struct resource *res_mem; int ret, irq_rx, irq_tx; + unsigned i, num_ports = 0; + u16 port_mask = BIT(8); + u8 val; /* stop if shared driver failed, assume driver->probe will be * called in the same order we register devices (correct ?) @@ -2808,6 +2826,43 @@ static int bcm_enetsw_probe(struct platf priv->pdev = pdev; priv->net_dev = dev; + /* reset mib */ + val = enetsw_readb(priv, ENETSW_GMCR_REG); + val |= ENETSW_GMCR_RST_MIB_MASK; + enetsw_writeb(priv, val, ENETSW_GMCR_REG); + mdelay(1); + val &= ~ENETSW_GMCR_RST_MIB_MASK; + enetsw_writeb(priv, val, ENETSW_GMCR_REG); + mdelay(1); + + /* force CPU port state */ + val = enetsw_readb(priv, ENETSW_IMPOV_REG); + val |= ENETSW_IMPOV_FORCE_MASK | ENETSW_IMPOV_LINKUP_MASK; + enetsw_writeb(priv, val, ENETSW_IMPOV_REG); + + /* enable switch forward engine */ + val = enetsw_readb(priv, ENETSW_SWMODE_REG); + val |= ENETSW_SWMODE_FWD_EN_MASK; + enetsw_writeb(priv, val, ENETSW_SWMODE_REG); + + /* enable jumbo on all ports */ + enetsw_writel(priv, 0x1ff, ENETSW_JMBCTL_PORT_REG); + enetsw_writew(priv, 9728, ENETSW_JMBCTL_MAXSIZE_REG); + + for (i = 0; i < priv->num_ports; i++) { + struct bcm63xx_enetsw_port *port = &priv->used_ports[i]; + + if (!port->used) + continue; + + num_ports++; + port_mask |= BIT(i); + } + + /* only register if there is more than one external port */ + if (num_ports > 1) + bcmenet_switch_register(priv, port_mask); + return 0; out_put_clk: @@ -2836,6 +2891,9 @@ static int bcm_enetsw_remove(struct plat priv = netdev_priv(dev); unregister_netdev(dev); + /* remove switch */ + bcmenet_switch_unregister(priv); + /* release device resources */ iounmap(priv->base); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);