1*9622972aSÁlvaro Fernández Rojas // SPDX-License-Identifier: GPL-2.0+ 2*9622972aSÁlvaro Fernández Rojas /* 3*9622972aSÁlvaro Fernández Rojas * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com> 4*9622972aSÁlvaro Fernández Rojas * 5*9622972aSÁlvaro Fernández Rojas * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c: 6*9622972aSÁlvaro Fernández Rojas * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7*9622972aSÁlvaro Fernández Rojas */ 8*9622972aSÁlvaro Fernández Rojas 9*9622972aSÁlvaro Fernández Rojas #include <common.h> 10*9622972aSÁlvaro Fernández Rojas #include <clk.h> 11*9622972aSÁlvaro Fernández Rojas #include <dm.h> 12*9622972aSÁlvaro Fernández Rojas #include <dma.h> 13*9622972aSÁlvaro Fernández Rojas #include <miiphy.h> 14*9622972aSÁlvaro Fernández Rojas #include <net.h> 15*9622972aSÁlvaro Fernández Rojas #include <reset.h> 16*9622972aSÁlvaro Fernández Rojas #include <wait_bit.h> 17*9622972aSÁlvaro Fernández Rojas #include <asm/io.h> 18*9622972aSÁlvaro Fernández Rojas 19*9622972aSÁlvaro Fernández Rojas #define ETH_PORT_STR "brcm,enetsw-port" 20*9622972aSÁlvaro Fernández Rojas 21*9622972aSÁlvaro Fernández Rojas #define ETH_RX_DESC PKTBUFSRX 22*9622972aSÁlvaro Fernández Rojas #define ETH_ZLEN 60 23*9622972aSÁlvaro Fernández Rojas #define ETH_TIMEOUT 100 24*9622972aSÁlvaro Fernández Rojas 25*9622972aSÁlvaro Fernández Rojas #define ETH_MAX_PORT 8 26*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_PORT0 4 27*9622972aSÁlvaro Fernández Rojas 28*9622972aSÁlvaro Fernández Rojas /* Port traffic control */ 29*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_REG(x) (0x0 + (x)) 30*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_SHIFT 0 31*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_RXDIS_MASK (1 << ETH_PTCTRL_RXDIS_SHIFT) 32*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_SHIFT 1 33*9622972aSÁlvaro Fernández Rojas #define ETH_PTCTRL_TXDIS_MASK (1 << ETH_PTCTRL_TXDIS_SHIFT) 34*9622972aSÁlvaro Fernández Rojas 35*9622972aSÁlvaro Fernández Rojas /* Switch mode register */ 36*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_REG 0xb 37*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_SHIFT 1 38*9622972aSÁlvaro Fernández Rojas #define ETH_SWMODE_FWD_EN_MASK (1 << ETH_SWMODE_FWD_EN_SHIFT) 39*9622972aSÁlvaro Fernández Rojas 40*9622972aSÁlvaro Fernández Rojas /* IMP override Register */ 41*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_REG 0xe 42*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_SHIFT 0 43*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_LINKUP_MASK (1 << ETH_IMPOV_LINKUP_SHIFT) 44*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_SHIFT 1 45*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FDX_MASK (1 << ETH_IMPOV_FDX_SHIFT) 46*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_SHIFT 2 47*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_100_MASK (1 << ETH_IMPOV_100_SHIFT) 48*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_SHIFT 3 49*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_1000_MASK (1 << ETH_IMPOV_1000_SHIFT) 50*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_SHIFT 4 51*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_RXFLOW_MASK (1 << ETH_IMPOV_RXFLOW_SHIFT) 52*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_SHIFT 5 53*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_TXFLOW_MASK (1 << ETH_IMPOV_TXFLOW_SHIFT) 54*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_SHIFT 7 55*9622972aSÁlvaro Fernández Rojas #define ETH_IMPOV_FORCE_MASK (1 << ETH_IMPOV_FORCE_SHIFT) 56*9622972aSÁlvaro Fernández Rojas 57*9622972aSÁlvaro Fernández Rojas /* Port override Register */ 58*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_REG(x) (0x58 + (x)) 59*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_SHIFT 0 60*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_LINKUP_MASK (1 << ETH_PORTOV_LINKUP_SHIFT) 61*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_SHIFT 1 62*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_FDX_MASK (1 << ETH_PORTOV_FDX_SHIFT) 63*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_SHIFT 2 64*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_100_MASK (1 << ETH_PORTOV_100_SHIFT) 65*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_SHIFT 3 66*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_1000_MASK (1 << ETH_PORTOV_1000_SHIFT) 67*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_SHIFT 4 68*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_RXFLOW_MASK (1 << ETH_PORTOV_RXFLOW_SHIFT) 69*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_SHIFT 5 70*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_TXFLOW_MASK (1 << ETH_PORTOV_TXFLOW_SHIFT) 71*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_SHIFT 6 72*9622972aSÁlvaro Fernández Rojas #define ETH_PORTOV_ENABLE_MASK (1 << ETH_PORTOV_ENABLE_SHIFT) 73*9622972aSÁlvaro Fernández Rojas 74*9622972aSÁlvaro Fernández Rojas /* Port RGMII control register */ 75*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_REG(x) (0x60 + (x)) 76*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_GMII_CLK_EN (1 << 7) 77*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_OVERRIDE_EN (1 << 6) 78*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE_MASK (3 << 4) 79*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RGMII_MODE (0 << 4) 80*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_MII_MODE (1 << 4) 81*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_RVMII_MODE (2 << 4) 82*9622972aSÁlvaro Fernández Rojas #define ETH_RGMII_CTRL_TIMING_SEL_EN (1 << 0) 83*9622972aSÁlvaro Fernández Rojas 84*9622972aSÁlvaro Fernández Rojas /* Port RGMII timing register */ 85*9622972aSÁlvaro Fernández Rojas #define ENETSW_RGMII_TIMING_REG(x) (0x68 + (x)) 86*9622972aSÁlvaro Fernández Rojas 87*9622972aSÁlvaro Fernández Rojas /* MDIO control register */ 88*9622972aSÁlvaro Fernández Rojas #define MII_SC_REG 0xb0 89*9622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_SHIFT 16 90*9622972aSÁlvaro Fernández Rojas #define MII_SC_EXT_MASK (1 << MII_SC_EXT_SHIFT) 91*9622972aSÁlvaro Fernández Rojas #define MII_SC_REG_SHIFT 20 92*9622972aSÁlvaro Fernández Rojas #define MII_SC_PHYID_SHIFT 25 93*9622972aSÁlvaro Fernández Rojas #define MII_SC_RD_SHIFT 30 94*9622972aSÁlvaro Fernández Rojas #define MII_SC_RD_MASK (1 << MII_SC_RD_SHIFT) 95*9622972aSÁlvaro Fernández Rojas #define MII_SC_WR_SHIFT 31 96*9622972aSÁlvaro Fernández Rojas #define MII_SC_WR_MASK (1 << MII_SC_WR_SHIFT) 97*9622972aSÁlvaro Fernández Rojas 98*9622972aSÁlvaro Fernández Rojas /* MDIO data register */ 99*9622972aSÁlvaro Fernández Rojas #define MII_DAT_REG 0xb4 100*9622972aSÁlvaro Fernández Rojas 101*9622972aSÁlvaro Fernández Rojas /* Global Management Configuration Register */ 102*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_REG 0x200 103*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_SHIFT 0 104*9622972aSÁlvaro Fernández Rojas #define ETH_GMCR_RST_MIB_MASK (1 << ETH_GMCR_RST_MIB_SHIFT) 105*9622972aSÁlvaro Fernández Rojas 106*9622972aSÁlvaro Fernández Rojas /* Jumbo control register port mask register */ 107*9622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_PORT_REG 0x4004 108*9622972aSÁlvaro Fernández Rojas 109*9622972aSÁlvaro Fernández Rojas /* Jumbo control mib good frame register */ 110*9622972aSÁlvaro Fernández Rojas #define ETH_JMBCTL_MAXSIZE_REG 0x4008 111*9622972aSÁlvaro Fernández Rojas 112*9622972aSÁlvaro Fernández Rojas /* ETH port data */ 113*9622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port { 114*9622972aSÁlvaro Fernández Rojas bool used; 115*9622972aSÁlvaro Fernández Rojas const char *name; 116*9622972aSÁlvaro Fernández Rojas /* Config */ 117*9622972aSÁlvaro Fernández Rojas bool bypass_link; 118*9622972aSÁlvaro Fernández Rojas int force_speed; 119*9622972aSÁlvaro Fernández Rojas bool force_duplex_full; 120*9622972aSÁlvaro Fernández Rojas /* PHY */ 121*9622972aSÁlvaro Fernández Rojas int phy_id; 122*9622972aSÁlvaro Fernández Rojas }; 123*9622972aSÁlvaro Fernández Rojas 124*9622972aSÁlvaro Fernández Rojas /* ETH data */ 125*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv { 126*9622972aSÁlvaro Fernández Rojas void __iomem *base; 127*9622972aSÁlvaro Fernández Rojas /* DMA */ 128*9622972aSÁlvaro Fernández Rojas struct dma rx_dma; 129*9622972aSÁlvaro Fernández Rojas struct dma tx_dma; 130*9622972aSÁlvaro Fernández Rojas /* Ports */ 131*9622972aSÁlvaro Fernández Rojas uint8_t num_ports; 132*9622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port used_ports[ETH_MAX_PORT]; 133*9622972aSÁlvaro Fernández Rojas int sw_port_link[ETH_MAX_PORT]; 134*9622972aSÁlvaro Fernández Rojas bool rgmii_override; 135*9622972aSÁlvaro Fernández Rojas bool rgmii_timing; 136*9622972aSÁlvaro Fernández Rojas /* PHY */ 137*9622972aSÁlvaro Fernández Rojas int phy_id; 138*9622972aSÁlvaro Fernández Rojas }; 139*9622972aSÁlvaro Fernández Rojas 140*9622972aSÁlvaro Fernández Rojas static inline bool bcm_enet_port_is_rgmii(int portid) 141*9622972aSÁlvaro Fernández Rojas { 142*9622972aSÁlvaro Fernández Rojas return portid >= ETH_RGMII_PORT0; 143*9622972aSÁlvaro Fernández Rojas } 144*9622972aSÁlvaro Fernández Rojas 145*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_read(struct bcm6368_eth_priv *priv, uint8_t ext, 146*9622972aSÁlvaro Fernández Rojas int phy_id, int reg) 147*9622972aSÁlvaro Fernández Rojas { 148*9622972aSÁlvaro Fernández Rojas uint32_t val; 149*9622972aSÁlvaro Fernández Rojas 150*9622972aSÁlvaro Fernández Rojas writel_be(0, priv->base + MII_SC_REG); 151*9622972aSÁlvaro Fernández Rojas 152*9622972aSÁlvaro Fernández Rojas val = MII_SC_RD_MASK | 153*9622972aSÁlvaro Fernández Rojas (phy_id << MII_SC_PHYID_SHIFT) | 154*9622972aSÁlvaro Fernández Rojas (reg << MII_SC_REG_SHIFT); 155*9622972aSÁlvaro Fernández Rojas 156*9622972aSÁlvaro Fernández Rojas if (ext) 157*9622972aSÁlvaro Fernández Rojas val |= MII_SC_EXT_MASK; 158*9622972aSÁlvaro Fernández Rojas 159*9622972aSÁlvaro Fernández Rojas writel_be(val, priv->base + MII_SC_REG); 160*9622972aSÁlvaro Fernández Rojas udelay(50); 161*9622972aSÁlvaro Fernández Rojas 162*9622972aSÁlvaro Fernández Rojas return readw_be(priv->base + MII_DAT_REG); 163*9622972aSÁlvaro Fernández Rojas } 164*9622972aSÁlvaro Fernández Rojas 165*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_write(struct bcm6368_eth_priv *priv, uint8_t ext, 166*9622972aSÁlvaro Fernández Rojas int phy_id, int reg, u16 data) 167*9622972aSÁlvaro Fernández Rojas { 168*9622972aSÁlvaro Fernández Rojas uint32_t val; 169*9622972aSÁlvaro Fernández Rojas 170*9622972aSÁlvaro Fernández Rojas writel_be(0, priv->base + MII_SC_REG); 171*9622972aSÁlvaro Fernández Rojas 172*9622972aSÁlvaro Fernández Rojas val = MII_SC_WR_MASK | 173*9622972aSÁlvaro Fernández Rojas (phy_id << MII_SC_PHYID_SHIFT) | 174*9622972aSÁlvaro Fernández Rojas (reg << MII_SC_REG_SHIFT); 175*9622972aSÁlvaro Fernández Rojas 176*9622972aSÁlvaro Fernández Rojas if (ext) 177*9622972aSÁlvaro Fernández Rojas val |= MII_SC_EXT_MASK; 178*9622972aSÁlvaro Fernández Rojas 179*9622972aSÁlvaro Fernández Rojas val |= data; 180*9622972aSÁlvaro Fernández Rojas 181*9622972aSÁlvaro Fernández Rojas writel_be(val, priv->base + MII_SC_REG); 182*9622972aSÁlvaro Fernández Rojas udelay(50); 183*9622972aSÁlvaro Fernández Rojas 184*9622972aSÁlvaro Fernández Rojas return 0; 185*9622972aSÁlvaro Fernández Rojas } 186*9622972aSÁlvaro Fernández Rojas 187*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_free_pkt(struct udevice *dev, uchar *packet, int len) 188*9622972aSÁlvaro Fernández Rojas { 189*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 190*9622972aSÁlvaro Fernández Rojas 191*9622972aSÁlvaro Fernández Rojas return dma_prepare_rcv_buf(&priv->rx_dma, packet, len); 192*9622972aSÁlvaro Fernández Rojas } 193*9622972aSÁlvaro Fernández Rojas 194*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_recv(struct udevice *dev, int flags, uchar **packetp) 195*9622972aSÁlvaro Fernández Rojas { 196*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 197*9622972aSÁlvaro Fernández Rojas 198*9622972aSÁlvaro Fernández Rojas return dma_receive(&priv->rx_dma, (void**)packetp, NULL); 199*9622972aSÁlvaro Fernández Rojas } 200*9622972aSÁlvaro Fernández Rojas 201*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_send(struct udevice *dev, void *packet, int length) 202*9622972aSÁlvaro Fernández Rojas { 203*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 204*9622972aSÁlvaro Fernández Rojas 205*9622972aSÁlvaro Fernández Rojas /* pad packets smaller than ETH_ZLEN */ 206*9622972aSÁlvaro Fernández Rojas if (length < ETH_ZLEN) { 207*9622972aSÁlvaro Fernández Rojas memset(packet + length, 0, ETH_ZLEN - length); 208*9622972aSÁlvaro Fernández Rojas length = ETH_ZLEN; 209*9622972aSÁlvaro Fernández Rojas } 210*9622972aSÁlvaro Fernández Rojas 211*9622972aSÁlvaro Fernández Rojas return dma_send(&priv->tx_dma, packet, length, NULL); 212*9622972aSÁlvaro Fernández Rojas } 213*9622972aSÁlvaro Fernández Rojas 214*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_adjust_link(struct udevice *dev) 215*9622972aSÁlvaro Fernández Rojas { 216*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 217*9622972aSÁlvaro Fernández Rojas unsigned int i; 218*9622972aSÁlvaro Fernández Rojas 219*9622972aSÁlvaro Fernández Rojas for (i = 0; i < priv->num_ports; i++) { 220*9622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port *port; 221*9622972aSÁlvaro Fernández Rojas int val, j, up, adv, lpa, speed, duplex, media; 222*9622972aSÁlvaro Fernández Rojas int external_phy = bcm_enet_port_is_rgmii(i); 223*9622972aSÁlvaro Fernández Rojas u8 override; 224*9622972aSÁlvaro Fernández Rojas 225*9622972aSÁlvaro Fernández Rojas port = &priv->used_ports[i]; 226*9622972aSÁlvaro Fernández Rojas if (!port->used) 227*9622972aSÁlvaro Fernández Rojas continue; 228*9622972aSÁlvaro Fernández Rojas 229*9622972aSÁlvaro Fernández Rojas if (port->bypass_link) 230*9622972aSÁlvaro Fernández Rojas continue; 231*9622972aSÁlvaro Fernández Rojas 232*9622972aSÁlvaro Fernández Rojas /* dummy read to clear */ 233*9622972aSÁlvaro Fernández Rojas for (j = 0; j < 2; j++) 234*9622972aSÁlvaro Fernández Rojas val = bcm6368_mdio_read(priv, external_phy, 235*9622972aSÁlvaro Fernández Rojas port->phy_id, MII_BMSR); 236*9622972aSÁlvaro Fernández Rojas 237*9622972aSÁlvaro Fernández Rojas if (val == 0xffff) 238*9622972aSÁlvaro Fernández Rojas continue; 239*9622972aSÁlvaro Fernández Rojas 240*9622972aSÁlvaro Fernández Rojas up = (val & BMSR_LSTATUS) ? 1 : 0; 241*9622972aSÁlvaro Fernández Rojas if (!(up ^ priv->sw_port_link[i])) 242*9622972aSÁlvaro Fernández Rojas continue; 243*9622972aSÁlvaro Fernández Rojas 244*9622972aSÁlvaro Fernández Rojas priv->sw_port_link[i] = up; 245*9622972aSÁlvaro Fernández Rojas 246*9622972aSÁlvaro Fernández Rojas /* link changed */ 247*9622972aSÁlvaro Fernández Rojas if (!up) { 248*9622972aSÁlvaro Fernández Rojas dev_info(&priv->pdev->dev, "link DOWN on %s\n", 249*9622972aSÁlvaro Fernández Rojas port->name); 250*9622972aSÁlvaro Fernández Rojas writeb_be(ETH_PORTOV_ENABLE_MASK, 251*9622972aSÁlvaro Fernández Rojas priv->base + ETH_PORTOV_REG(i)); 252*9622972aSÁlvaro Fernández Rojas writeb_be(ETH_PTCTRL_RXDIS_MASK | 253*9622972aSÁlvaro Fernández Rojas ETH_PTCTRL_TXDIS_MASK, 254*9622972aSÁlvaro Fernández Rojas priv->base + ETH_PTCTRL_REG(i)); 255*9622972aSÁlvaro Fernández Rojas continue; 256*9622972aSÁlvaro Fernández Rojas } 257*9622972aSÁlvaro Fernández Rojas 258*9622972aSÁlvaro Fernández Rojas adv = bcm6368_mdio_read(priv, external_phy, 259*9622972aSÁlvaro Fernández Rojas port->phy_id, MII_ADVERTISE); 260*9622972aSÁlvaro Fernández Rojas 261*9622972aSÁlvaro Fernández Rojas lpa = bcm6368_mdio_read(priv, external_phy, port->phy_id, 262*9622972aSÁlvaro Fernández Rojas MII_LPA); 263*9622972aSÁlvaro Fernández Rojas 264*9622972aSÁlvaro Fernández Rojas /* figure out media and duplex from advertise and LPA values */ 265*9622972aSÁlvaro Fernández Rojas media = mii_nway_result(lpa & adv); 266*9622972aSÁlvaro Fernández Rojas duplex = (media & ADVERTISE_FULL) ? 1 : 0; 267*9622972aSÁlvaro Fernández Rojas 268*9622972aSÁlvaro Fernández Rojas if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) 269*9622972aSÁlvaro Fernández Rojas speed = 100; 270*9622972aSÁlvaro Fernández Rojas else 271*9622972aSÁlvaro Fernández Rojas speed = 10; 272*9622972aSÁlvaro Fernández Rojas 273*9622972aSÁlvaro Fernández Rojas if (val & BMSR_ESTATEN) { 274*9622972aSÁlvaro Fernández Rojas adv = bcm6368_mdio_read(priv, external_phy, 275*9622972aSÁlvaro Fernández Rojas port->phy_id, MII_CTRL1000); 276*9622972aSÁlvaro Fernández Rojas 277*9622972aSÁlvaro Fernández Rojas lpa = bcm6368_mdio_read(priv, external_phy, 278*9622972aSÁlvaro Fernández Rojas port->phy_id, MII_STAT1000); 279*9622972aSÁlvaro Fernández Rojas 280*9622972aSÁlvaro Fernández Rojas if ((adv & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) && 281*9622972aSÁlvaro Fernández Rojas (lpa & (LPA_1000FULL | LPA_1000HALF))) { 282*9622972aSÁlvaro Fernández Rojas speed = 1000; 283*9622972aSÁlvaro Fernández Rojas duplex = (lpa & LPA_1000FULL); 284*9622972aSÁlvaro Fernández Rojas } 285*9622972aSÁlvaro Fernández Rojas } 286*9622972aSÁlvaro Fernández Rojas 287*9622972aSÁlvaro Fernández Rojas pr_alert("link UP on %s, %dMbps, %s-duplex\n", 288*9622972aSÁlvaro Fernández Rojas port->name, speed, duplex ? "full" : "half"); 289*9622972aSÁlvaro Fernández Rojas 290*9622972aSÁlvaro Fernández Rojas override = ETH_PORTOV_ENABLE_MASK | 291*9622972aSÁlvaro Fernández Rojas ETH_PORTOV_LINKUP_MASK; 292*9622972aSÁlvaro Fernández Rojas 293*9622972aSÁlvaro Fernández Rojas if (speed == 1000) 294*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_1000_MASK; 295*9622972aSÁlvaro Fernández Rojas else if (speed == 100) 296*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_100_MASK; 297*9622972aSÁlvaro Fernández Rojas if (duplex) 298*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_FDX_MASK; 299*9622972aSÁlvaro Fernández Rojas 300*9622972aSÁlvaro Fernández Rojas writeb_be(override, priv->base + ETH_PORTOV_REG(i)); 301*9622972aSÁlvaro Fernández Rojas writeb_be(0, priv->base + ETH_PTCTRL_REG(i)); 302*9622972aSÁlvaro Fernández Rojas } 303*9622972aSÁlvaro Fernández Rojas 304*9622972aSÁlvaro Fernández Rojas return 0; 305*9622972aSÁlvaro Fernández Rojas } 306*9622972aSÁlvaro Fernández Rojas 307*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_start(struct udevice *dev) 308*9622972aSÁlvaro Fernández Rojas { 309*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 310*9622972aSÁlvaro Fernández Rojas uint8_t i; 311*9622972aSÁlvaro Fernández Rojas 312*9622972aSÁlvaro Fernández Rojas /* prepare rx dma buffers */ 313*9622972aSÁlvaro Fernández Rojas for (i = 0; i < ETH_RX_DESC; i++) { 314*9622972aSÁlvaro Fernández Rojas int ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i], 315*9622972aSÁlvaro Fernández Rojas PKTSIZE_ALIGN); 316*9622972aSÁlvaro Fernández Rojas if (ret < 0) 317*9622972aSÁlvaro Fernández Rojas break; 318*9622972aSÁlvaro Fernández Rojas } 319*9622972aSÁlvaro Fernández Rojas 320*9622972aSÁlvaro Fernández Rojas /* enable dma rx channel */ 321*9622972aSÁlvaro Fernández Rojas dma_enable(&priv->rx_dma); 322*9622972aSÁlvaro Fernández Rojas 323*9622972aSÁlvaro Fernández Rojas /* enable dma tx channel */ 324*9622972aSÁlvaro Fernández Rojas dma_enable(&priv->tx_dma); 325*9622972aSÁlvaro Fernández Rojas 326*9622972aSÁlvaro Fernández Rojas /* apply override config for bypass_link ports here. */ 327*9622972aSÁlvaro Fernández Rojas for (i = 0; i < priv->num_ports; i++) { 328*9622972aSÁlvaro Fernández Rojas struct bcm_enetsw_port *port; 329*9622972aSÁlvaro Fernández Rojas u8 override; 330*9622972aSÁlvaro Fernández Rojas 331*9622972aSÁlvaro Fernández Rojas port = &priv->used_ports[i]; 332*9622972aSÁlvaro Fernández Rojas if (!port->used) 333*9622972aSÁlvaro Fernández Rojas continue; 334*9622972aSÁlvaro Fernández Rojas 335*9622972aSÁlvaro Fernández Rojas if (!port->bypass_link) 336*9622972aSÁlvaro Fernández Rojas continue; 337*9622972aSÁlvaro Fernández Rojas 338*9622972aSÁlvaro Fernández Rojas override = ETH_PORTOV_ENABLE_MASK | 339*9622972aSÁlvaro Fernández Rojas ETH_PORTOV_LINKUP_MASK; 340*9622972aSÁlvaro Fernández Rojas 341*9622972aSÁlvaro Fernández Rojas switch (port->force_speed) { 342*9622972aSÁlvaro Fernández Rojas case 1000: 343*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_1000_MASK; 344*9622972aSÁlvaro Fernández Rojas break; 345*9622972aSÁlvaro Fernández Rojas case 100: 346*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_100_MASK; 347*9622972aSÁlvaro Fernández Rojas break; 348*9622972aSÁlvaro Fernández Rojas case 10: 349*9622972aSÁlvaro Fernández Rojas break; 350*9622972aSÁlvaro Fernández Rojas default: 351*9622972aSÁlvaro Fernández Rojas pr_warn("%s: invalid forced speed on port %s\n", 352*9622972aSÁlvaro Fernández Rojas __func__, port->name); 353*9622972aSÁlvaro Fernández Rojas break; 354*9622972aSÁlvaro Fernández Rojas } 355*9622972aSÁlvaro Fernández Rojas 356*9622972aSÁlvaro Fernández Rojas if (port->force_duplex_full) 357*9622972aSÁlvaro Fernández Rojas override |= ETH_PORTOV_FDX_MASK; 358*9622972aSÁlvaro Fernández Rojas 359*9622972aSÁlvaro Fernández Rojas writeb_be(override, priv->base + ETH_PORTOV_REG(i)); 360*9622972aSÁlvaro Fernández Rojas writeb_be(0, priv->base + ETH_PTCTRL_REG(i)); 361*9622972aSÁlvaro Fernández Rojas } 362*9622972aSÁlvaro Fernández Rojas 363*9622972aSÁlvaro Fernández Rojas bcm6368_eth_adjust_link(dev); 364*9622972aSÁlvaro Fernández Rojas 365*9622972aSÁlvaro Fernández Rojas return 0; 366*9622972aSÁlvaro Fernández Rojas } 367*9622972aSÁlvaro Fernández Rojas 368*9622972aSÁlvaro Fernández Rojas static void bcm6368_eth_stop(struct udevice *dev) 369*9622972aSÁlvaro Fernández Rojas { 370*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 371*9622972aSÁlvaro Fernández Rojas 372*9622972aSÁlvaro Fernández Rojas /* disable dma rx channel */ 373*9622972aSÁlvaro Fernández Rojas dma_disable(&priv->rx_dma); 374*9622972aSÁlvaro Fernández Rojas 375*9622972aSÁlvaro Fernández Rojas /* disable dma tx channel */ 376*9622972aSÁlvaro Fernández Rojas dma_disable(&priv->tx_dma); 377*9622972aSÁlvaro Fernández Rojas } 378*9622972aSÁlvaro Fernández Rojas 379*9622972aSÁlvaro Fernández Rojas static const struct eth_ops bcm6368_eth_ops = { 380*9622972aSÁlvaro Fernández Rojas .free_pkt = bcm6368_eth_free_pkt, 381*9622972aSÁlvaro Fernández Rojas .recv = bcm6368_eth_recv, 382*9622972aSÁlvaro Fernández Rojas .send = bcm6368_eth_send, 383*9622972aSÁlvaro Fernández Rojas .start = bcm6368_eth_start, 384*9622972aSÁlvaro Fernández Rojas .stop = bcm6368_eth_stop, 385*9622972aSÁlvaro Fernández Rojas }; 386*9622972aSÁlvaro Fernández Rojas 387*9622972aSÁlvaro Fernández Rojas static const struct udevice_id bcm6368_eth_ids[] = { 388*9622972aSÁlvaro Fernández Rojas { .compatible = "brcm,bcm6368-enet", }, 389*9622972aSÁlvaro Fernández Rojas { /* sentinel */ } 390*9622972aSÁlvaro Fernández Rojas }; 391*9622972aSÁlvaro Fernández Rojas 392*9622972aSÁlvaro Fernández Rojas static bool bcm6368_phy_is_external(struct bcm6368_eth_priv *priv, int phy_id) 393*9622972aSÁlvaro Fernández Rojas { 394*9622972aSÁlvaro Fernández Rojas uint8_t i; 395*9622972aSÁlvaro Fernández Rojas 396*9622972aSÁlvaro Fernández Rojas for (i = 0; i < priv->num_ports; ++i) { 397*9622972aSÁlvaro Fernández Rojas if (!priv->used_ports[i].used) 398*9622972aSÁlvaro Fernández Rojas continue; 399*9622972aSÁlvaro Fernández Rojas if (priv->used_ports[i].phy_id == phy_id) 400*9622972aSÁlvaro Fernández Rojas return bcm_enet_port_is_rgmii(i); 401*9622972aSÁlvaro Fernández Rojas } 402*9622972aSÁlvaro Fernández Rojas 403*9622972aSÁlvaro Fernández Rojas return true; 404*9622972aSÁlvaro Fernández Rojas } 405*9622972aSÁlvaro Fernández Rojas 406*9622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_read(struct mii_dev *bus, int addr, int devaddr, 407*9622972aSÁlvaro Fernández Rojas int reg) 408*9622972aSÁlvaro Fernández Rojas { 409*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = bus->priv; 410*9622972aSÁlvaro Fernández Rojas bool ext = bcm6368_phy_is_external(priv, addr); 411*9622972aSÁlvaro Fernández Rojas 412*9622972aSÁlvaro Fernández Rojas return bcm6368_mdio_read(priv, ext, addr, reg); 413*9622972aSÁlvaro Fernández Rojas } 414*9622972aSÁlvaro Fernández Rojas 415*9622972aSÁlvaro Fernández Rojas static int bcm6368_mii_mdio_write(struct mii_dev *bus, int addr, int devaddr, 416*9622972aSÁlvaro Fernández Rojas int reg, u16 data) 417*9622972aSÁlvaro Fernández Rojas { 418*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = bus->priv; 419*9622972aSÁlvaro Fernández Rojas bool ext = bcm6368_phy_is_external(priv, addr); 420*9622972aSÁlvaro Fernández Rojas 421*9622972aSÁlvaro Fernández Rojas return bcm6368_mdio_write(priv, ext, addr, reg, data); 422*9622972aSÁlvaro Fernández Rojas } 423*9622972aSÁlvaro Fernández Rojas 424*9622972aSÁlvaro Fernández Rojas static int bcm6368_mdio_init(const char *name, struct bcm6368_eth_priv *priv) 425*9622972aSÁlvaro Fernández Rojas { 426*9622972aSÁlvaro Fernández Rojas struct mii_dev *bus; 427*9622972aSÁlvaro Fernández Rojas 428*9622972aSÁlvaro Fernández Rojas bus = mdio_alloc(); 429*9622972aSÁlvaro Fernández Rojas if (!bus) { 430*9622972aSÁlvaro Fernández Rojas pr_err("%s: failed to allocate MDIO bus\n", __func__); 431*9622972aSÁlvaro Fernández Rojas return -ENOMEM; 432*9622972aSÁlvaro Fernández Rojas } 433*9622972aSÁlvaro Fernández Rojas 434*9622972aSÁlvaro Fernández Rojas bus->read = bcm6368_mii_mdio_read; 435*9622972aSÁlvaro Fernández Rojas bus->write = bcm6368_mii_mdio_write; 436*9622972aSÁlvaro Fernández Rojas bus->priv = priv; 437*9622972aSÁlvaro Fernández Rojas snprintf(bus->name, sizeof(bus->name), "%s", name); 438*9622972aSÁlvaro Fernández Rojas 439*9622972aSÁlvaro Fernández Rojas return mdio_register(bus); 440*9622972aSÁlvaro Fernández Rojas } 441*9622972aSÁlvaro Fernández Rojas 442*9622972aSÁlvaro Fernández Rojas static int bcm6368_eth_probe(struct udevice *dev) 443*9622972aSÁlvaro Fernández Rojas { 444*9622972aSÁlvaro Fernández Rojas struct eth_pdata *pdata = dev_get_platdata(dev); 445*9622972aSÁlvaro Fernández Rojas struct bcm6368_eth_priv *priv = dev_get_priv(dev); 446*9622972aSÁlvaro Fernández Rojas int num_ports, ret, i; 447*9622972aSÁlvaro Fernández Rojas uint32_t val; 448*9622972aSÁlvaro Fernández Rojas ofnode node; 449*9622972aSÁlvaro Fernández Rojas 450*9622972aSÁlvaro Fernández Rojas /* get base address */ 451*9622972aSÁlvaro Fernández Rojas priv->base = dev_remap_addr(dev); 452*9622972aSÁlvaro Fernández Rojas if (!priv->base) 453*9622972aSÁlvaro Fernández Rojas return -EINVAL; 454*9622972aSÁlvaro Fernández Rojas pdata->iobase = (phys_addr_t) priv->base; 455*9622972aSÁlvaro Fernández Rojas 456*9622972aSÁlvaro Fernández Rojas /* get number of ports */ 457*9622972aSÁlvaro Fernández Rojas num_ports = dev_read_u32_default(dev, "brcm,num-ports", ETH_MAX_PORT); 458*9622972aSÁlvaro Fernández Rojas if (!num_ports || num_ports > ETH_MAX_PORT) 459*9622972aSÁlvaro Fernández Rojas return -EINVAL; 460*9622972aSÁlvaro Fernández Rojas 461*9622972aSÁlvaro Fernández Rojas /* get dma channels */ 462*9622972aSÁlvaro Fernández Rojas ret = dma_get_by_name(dev, "tx", &priv->tx_dma); 463*9622972aSÁlvaro Fernández Rojas if (ret) 464*9622972aSÁlvaro Fernández Rojas return -EINVAL; 465*9622972aSÁlvaro Fernández Rojas 466*9622972aSÁlvaro Fernández Rojas ret = dma_get_by_name(dev, "rx", &priv->rx_dma); 467*9622972aSÁlvaro Fernández Rojas if (ret) 468*9622972aSÁlvaro Fernández Rojas return -EINVAL; 469*9622972aSÁlvaro Fernández Rojas 470*9622972aSÁlvaro Fernández Rojas /* try to enable clocks */ 471*9622972aSÁlvaro Fernández Rojas for (i = 0; ; i++) { 472*9622972aSÁlvaro Fernández Rojas struct clk clk; 473*9622972aSÁlvaro Fernández Rojas int ret; 474*9622972aSÁlvaro Fernández Rojas 475*9622972aSÁlvaro Fernández Rojas ret = clk_get_by_index(dev, i, &clk); 476*9622972aSÁlvaro Fernández Rojas if (ret < 0) 477*9622972aSÁlvaro Fernández Rojas break; 478*9622972aSÁlvaro Fernández Rojas 479*9622972aSÁlvaro Fernández Rojas ret = clk_enable(&clk); 480*9622972aSÁlvaro Fernández Rojas if (ret < 0) { 481*9622972aSÁlvaro Fernández Rojas pr_err("%s: error enabling clock %d\n", __func__, i); 482*9622972aSÁlvaro Fernández Rojas return ret; 483*9622972aSÁlvaro Fernández Rojas } 484*9622972aSÁlvaro Fernández Rojas 485*9622972aSÁlvaro Fernández Rojas ret = clk_free(&clk); 486*9622972aSÁlvaro Fernández Rojas if (ret < 0) { 487*9622972aSÁlvaro Fernández Rojas pr_err("%s: error freeing clock %d\n", __func__, i); 488*9622972aSÁlvaro Fernández Rojas return ret; 489*9622972aSÁlvaro Fernández Rojas } 490*9622972aSÁlvaro Fernández Rojas } 491*9622972aSÁlvaro Fernández Rojas 492*9622972aSÁlvaro Fernández Rojas /* try to perform resets */ 493*9622972aSÁlvaro Fernández Rojas for (i = 0; ; i++) { 494*9622972aSÁlvaro Fernández Rojas struct reset_ctl reset; 495*9622972aSÁlvaro Fernández Rojas int ret; 496*9622972aSÁlvaro Fernández Rojas 497*9622972aSÁlvaro Fernández Rojas ret = reset_get_by_index(dev, i, &reset); 498*9622972aSÁlvaro Fernández Rojas if (ret < 0) 499*9622972aSÁlvaro Fernández Rojas break; 500*9622972aSÁlvaro Fernández Rojas 501*9622972aSÁlvaro Fernández Rojas ret = reset_deassert(&reset); 502*9622972aSÁlvaro Fernández Rojas if (ret < 0) { 503*9622972aSÁlvaro Fernández Rojas pr_err("%s: error deasserting reset %d\n", __func__, i); 504*9622972aSÁlvaro Fernández Rojas return ret; 505*9622972aSÁlvaro Fernández Rojas } 506*9622972aSÁlvaro Fernández Rojas 507*9622972aSÁlvaro Fernández Rojas ret = reset_free(&reset); 508*9622972aSÁlvaro Fernández Rojas if (ret < 0) { 509*9622972aSÁlvaro Fernández Rojas pr_err("%s: error freeing reset %d\n", __func__, i); 510*9622972aSÁlvaro Fernández Rojas return ret; 511*9622972aSÁlvaro Fernández Rojas } 512*9622972aSÁlvaro Fernández Rojas } 513*9622972aSÁlvaro Fernández Rojas 514*9622972aSÁlvaro Fernández Rojas /* set priv data */ 515*9622972aSÁlvaro Fernández Rojas priv->num_ports = num_ports; 516*9622972aSÁlvaro Fernández Rojas if (dev_read_bool(dev, "brcm,rgmii-override")) 517*9622972aSÁlvaro Fernández Rojas priv->rgmii_override = true; 518*9622972aSÁlvaro Fernández Rojas if (dev_read_bool(dev, "brcm,rgmii-timing")) 519*9622972aSÁlvaro Fernández Rojas priv->rgmii_timing = true; 520*9622972aSÁlvaro Fernández Rojas 521*9622972aSÁlvaro Fernández Rojas /* get ports */ 522*9622972aSÁlvaro Fernández Rojas dev_for_each_subnode(node, dev) { 523*9622972aSÁlvaro Fernández Rojas const char *comp; 524*9622972aSÁlvaro Fernández Rojas const char *label; 525*9622972aSÁlvaro Fernández Rojas unsigned int p; 526*9622972aSÁlvaro Fernández Rojas int phy_id; 527*9622972aSÁlvaro Fernández Rojas int speed; 528*9622972aSÁlvaro Fernández Rojas 529*9622972aSÁlvaro Fernández Rojas comp = ofnode_read_string(node, "compatible"); 530*9622972aSÁlvaro Fernández Rojas if (!comp || memcmp(comp, ETH_PORT_STR, sizeof(ETH_PORT_STR))) 531*9622972aSÁlvaro Fernández Rojas continue; 532*9622972aSÁlvaro Fernández Rojas 533*9622972aSÁlvaro Fernández Rojas p = ofnode_read_u32_default(node, "reg", ETH_MAX_PORT); 534*9622972aSÁlvaro Fernández Rojas if (p >= num_ports) 535*9622972aSÁlvaro Fernández Rojas return -EINVAL; 536*9622972aSÁlvaro Fernández Rojas 537*9622972aSÁlvaro Fernández Rojas label = ofnode_read_string(node, "label"); 538*9622972aSÁlvaro Fernández Rojas if (!label) { 539*9622972aSÁlvaro Fernández Rojas debug("%s: node %s has no label\n", __func__, 540*9622972aSÁlvaro Fernández Rojas ofnode_get_name(node)); 541*9622972aSÁlvaro Fernández Rojas return -EINVAL; 542*9622972aSÁlvaro Fernández Rojas } 543*9622972aSÁlvaro Fernández Rojas 544*9622972aSÁlvaro Fernández Rojas phy_id = ofnode_read_u32_default(node, "brcm,phy-id", -1); 545*9622972aSÁlvaro Fernández Rojas 546*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].used = true; 547*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].name = label; 548*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].phy_id = phy_id; 549*9622972aSÁlvaro Fernández Rojas 550*9622972aSÁlvaro Fernández Rojas if (ofnode_read_bool(node, "full-duplex")) 551*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].force_duplex_full = true; 552*9622972aSÁlvaro Fernández Rojas if (ofnode_read_bool(node, "bypass-link")) 553*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].bypass_link = true; 554*9622972aSÁlvaro Fernández Rojas speed = ofnode_read_u32_default(node, "speed", 0); 555*9622972aSÁlvaro Fernández Rojas if (speed) 556*9622972aSÁlvaro Fernández Rojas priv->used_ports[p].force_speed = speed; 557*9622972aSÁlvaro Fernández Rojas } 558*9622972aSÁlvaro Fernández Rojas 559*9622972aSÁlvaro Fernández Rojas /* init mii bus */ 560*9622972aSÁlvaro Fernández Rojas ret = bcm6368_mdio_init(dev->name, priv); 561*9622972aSÁlvaro Fernández Rojas if (ret) 562*9622972aSÁlvaro Fernández Rojas return ret; 563*9622972aSÁlvaro Fernández Rojas 564*9622972aSÁlvaro Fernández Rojas /* disable all ports */ 565*9622972aSÁlvaro Fernández Rojas for (i = 0; i < priv->num_ports; i++) { 566*9622972aSÁlvaro Fernández Rojas writeb_be(ETH_PORTOV_ENABLE_MASK, 567*9622972aSÁlvaro Fernández Rojas priv->base + ETH_PORTOV_REG(i)); 568*9622972aSÁlvaro Fernández Rojas writeb_be(ETH_PTCTRL_RXDIS_MASK | 569*9622972aSÁlvaro Fernández Rojas ETH_PTCTRL_TXDIS_MASK, 570*9622972aSÁlvaro Fernández Rojas priv->base + ETH_PTCTRL_REG(i)); 571*9622972aSÁlvaro Fernández Rojas 572*9622972aSÁlvaro Fernández Rojas priv->sw_port_link[i] = 0; 573*9622972aSÁlvaro Fernández Rojas } 574*9622972aSÁlvaro Fernández Rojas 575*9622972aSÁlvaro Fernández Rojas /* enable external ports */ 576*9622972aSÁlvaro Fernández Rojas for (i = ETH_RGMII_PORT0; i < priv->num_ports; i++) { 577*9622972aSÁlvaro Fernández Rojas u8 rgmii_ctrl; 578*9622972aSÁlvaro Fernández Rojas 579*9622972aSÁlvaro Fernández Rojas if (!priv->used_ports[i].used) 580*9622972aSÁlvaro Fernández Rojas continue; 581*9622972aSÁlvaro Fernández Rojas 582*9622972aSÁlvaro Fernández Rojas rgmii_ctrl = readb_be(priv->base + ETH_RGMII_CTRL_REG(i)); 583*9622972aSÁlvaro Fernández Rojas rgmii_ctrl |= ETH_RGMII_CTRL_GMII_CLK_EN; 584*9622972aSÁlvaro Fernández Rojas if (priv->rgmii_override) 585*9622972aSÁlvaro Fernández Rojas rgmii_ctrl |= ETH_RGMII_CTRL_MII_OVERRIDE_EN; 586*9622972aSÁlvaro Fernández Rojas if (priv->rgmii_timing) 587*9622972aSÁlvaro Fernández Rojas rgmii_ctrl |= ETH_RGMII_CTRL_TIMING_SEL_EN; 588*9622972aSÁlvaro Fernández Rojas writeb_be(rgmii_ctrl, priv->base + ETH_RGMII_CTRL_REG(i)); 589*9622972aSÁlvaro Fernández Rojas } 590*9622972aSÁlvaro Fernández Rojas 591*9622972aSÁlvaro Fernández Rojas /* reset mib */ 592*9622972aSÁlvaro Fernández Rojas val = readb_be(priv->base + ETH_GMCR_REG); 593*9622972aSÁlvaro Fernández Rojas val |= ETH_GMCR_RST_MIB_MASK; 594*9622972aSÁlvaro Fernández Rojas writeb_be(val, priv->base + ETH_GMCR_REG); 595*9622972aSÁlvaro Fernández Rojas mdelay(1); 596*9622972aSÁlvaro Fernández Rojas val &= ~ETH_GMCR_RST_MIB_MASK; 597*9622972aSÁlvaro Fernández Rojas writeb_be(val, priv->base + ETH_GMCR_REG); 598*9622972aSÁlvaro Fernández Rojas mdelay(1); 599*9622972aSÁlvaro Fernández Rojas 600*9622972aSÁlvaro Fernández Rojas /* force CPU port state */ 601*9622972aSÁlvaro Fernández Rojas val = readb_be(priv->base + ETH_IMPOV_REG); 602*9622972aSÁlvaro Fernández Rojas val |= ETH_IMPOV_FORCE_MASK | ETH_IMPOV_LINKUP_MASK; 603*9622972aSÁlvaro Fernández Rojas writeb_be(val, priv->base + ETH_IMPOV_REG); 604*9622972aSÁlvaro Fernández Rojas 605*9622972aSÁlvaro Fernández Rojas /* enable switch forward engine */ 606*9622972aSÁlvaro Fernández Rojas val = readb_be(priv->base + ETH_SWMODE_REG); 607*9622972aSÁlvaro Fernández Rojas val |= ETH_SWMODE_FWD_EN_MASK; 608*9622972aSÁlvaro Fernández Rojas writeb_be(val, priv->base + ETH_SWMODE_REG); 609*9622972aSÁlvaro Fernández Rojas 610*9622972aSÁlvaro Fernández Rojas /* enable jumbo on all ports */ 611*9622972aSÁlvaro Fernández Rojas writel_be(0x1ff, priv->base + ETH_JMBCTL_PORT_REG); 612*9622972aSÁlvaro Fernández Rojas writew_be(9728, priv->base + ETH_JMBCTL_MAXSIZE_REG); 613*9622972aSÁlvaro Fernández Rojas 614*9622972aSÁlvaro Fernández Rojas return 0; 615*9622972aSÁlvaro Fernández Rojas } 616*9622972aSÁlvaro Fernández Rojas 617*9622972aSÁlvaro Fernández Rojas U_BOOT_DRIVER(bcm6368_eth) = { 618*9622972aSÁlvaro Fernández Rojas .name = "bcm6368_eth", 619*9622972aSÁlvaro Fernández Rojas .id = UCLASS_ETH, 620*9622972aSÁlvaro Fernández Rojas .of_match = bcm6368_eth_ids, 621*9622972aSÁlvaro Fernández Rojas .ops = &bcm6368_eth_ops, 622*9622972aSÁlvaro Fernández Rojas .platdata_auto_alloc_size = sizeof(struct eth_pdata), 623*9622972aSÁlvaro Fernández Rojas .priv_auto_alloc_size = sizeof(struct bcm6368_eth_priv), 624*9622972aSÁlvaro Fernández Rojas .probe = bcm6368_eth_probe, 625*9622972aSÁlvaro Fernández Rojas }; 626