diff options
author | Tom Rini <trini@konsulko.com> | 2018-01-15 19:01:23 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2018-01-15 19:01:23 -0500 |
commit | fdb6c3232f66bc9c07c30de87928506477ac4e63 (patch) | |
tree | c3874d5f8a75daadab700fb0a08e65f0e6d9cb9f /drivers | |
parent | 8e9801c283c0e5a7ccd5c04f5ba09003d01f1591 (diff) | |
parent | 1e2d2597a667e16adfe0a8a9be22e904cee84727 (diff) |
Merge git://git.denx.de/u-boot-net
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/read.c | 7 | ||||
-rw-r--r-- | drivers/net/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/designware.c | 48 | ||||
-rw-r--r-- | drivers/net/designware.h | 4 | ||||
-rw-r--r-- | drivers/net/macb.c | 91 | ||||
-rw-r--r-- | drivers/net/macb.h | 1 | ||||
-rw-r--r-- | drivers/net/mvneta.c | 6 | ||||
-rw-r--r-- | drivers/net/netconsole.c | 7 | ||||
-rw-r--r-- | drivers/net/phy/Kconfig | 17 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/atheros.c | 1 | ||||
-rw-r--r-- | drivers/net/phy/b53.c | 768 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 29 | ||||
-rw-r--r-- | drivers/net/phy/miiphybb.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 3 | ||||
-rw-r--r-- | drivers/net/sh_eth.c | 155 | ||||
-rw-r--r-- | drivers/net/sh_eth.h | 76 |
17 files changed, 1083 insertions, 146 deletions
diff --git a/drivers/core/read.c b/drivers/core/read.c index 5d440cee721..f346cc1eb69 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -103,6 +103,13 @@ int dev_read_phandle_with_args(struct udevice *dev, const char *list_name, out_args); } +int dev_count_phandle_with_args(struct udevice *dev, const char *list_name, + const char *cells_name) +{ + return ofnode_count_phandle_with_args(dev_ofnode(dev), list_name, + cells_name); +} + int dev_read_addr_cells(struct udevice *dev) { return ofnode_read_addr_cells(dev_ofnode(dev)); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 46b17b17ada..de1947ccc17 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -185,6 +185,13 @@ config MACB GEM (Gigabit Ethernet MAC) found in some ARM SoC devices. Say Y to include support for the MACB/GEM chip. +config MACB_ZYNQ + bool "Cadence MACB/GEM Ethernet Interface for Xilinx Zynq" + depends on MACB + help + The Cadence MACB ethernet interface was used on Zynq platform. + Say Y to enable support for the MACB/GEM in Zynq chip. + config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCI @@ -269,6 +276,12 @@ config SUN8I_EMAC It can be found in H3/A64/A83T based SoCs and compatible with both External and Internal PHYs. +config SH_ETHER + bool "Renesas SH Ethernet MAC" + select PHYLIB + help + This driver supports the Ethernet for Renesas SH and ARM SoCs. + config XILINX_AXIEMAC depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) select PHYLIB diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 036d231071c..6d5307128d8 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -10,6 +10,7 @@ */ #include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <miiphy.h> @@ -17,6 +18,7 @@ #include <pci.h> #include <linux/compiler.h> #include <linux/err.h> +#include <linux/kernel.h> #include <asm/io.h> #include <power/regulator.h> #include "designware.h" @@ -343,6 +345,8 @@ int designware_eth_enable(struct dw_eth_dev *priv) return 0; } +#define ETH_ZLEN 60 + static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length) { struct eth_dma_regs *dma_p = priv->dma_regs_p; @@ -369,6 +373,8 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length) return -EPERM; } + length = max(length, ETH_ZLEN); + memcpy((void *)data_start, packet, length); /* Flush data to be sent */ @@ -661,6 +667,35 @@ int designware_eth_probe(struct udevice *dev) u32 iobase = pdata->iobase; ulong ioaddr; int ret; +#ifdef CONFIG_CLK + int i, err, clock_nb; + + priv->clock_count = 0; + clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + if (err < 0) + break; + + err = clk_enable(&priv->clocks[i]); + if (err) { + pr_err("failed to enable clock %d\n", i); + clk_free(&priv->clocks[i]); + goto clk_err; + } + priv->clock_count++; + } + } else if (clock_nb != -ENOENT) { + pr_err("failed to get clock phandle(%d)\n", clock_nb); + return clock_nb; + } +#endif #if defined(CONFIG_DM_REGULATOR) struct udevice *phy_supply; @@ -707,6 +742,15 @@ int designware_eth_probe(struct udevice *dev) debug("%s, ret=%d\n", __func__, ret); return ret; + +#ifdef CONFIG_CLK +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + pr_err("failed to disable all clocks\n"); + + return err; +#endif } static int designware_eth_remove(struct udevice *dev) @@ -717,7 +761,11 @@ static int designware_eth_remove(struct udevice *dev) mdio_unregister(priv->bus); mdio_free(priv->bus); +#ifdef CONFIG_CLK + return clk_release_all(priv->clocks, priv->clock_count); +#else return 0; +#endif } const struct eth_ops designware_eth_ops = { diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 7992d0ebeeb..252cd24f1aa 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -239,6 +239,10 @@ struct dw_eth_dev { #ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio; #endif +#ifdef CONFIG_CLK + struct clk *clocks; /* clock list */ + int clock_count; /* number of clock in clock list */ +#endif struct phy_device *phydev; struct mii_dev *bus; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index f9373db0b93..e62aefcd0d6 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -52,6 +52,22 @@ DECLARE_GLOBAL_DATA_PTR; #define MACB_TX_TIMEOUT 1000 #define MACB_AUTONEG_TIMEOUT 5000000 +#ifdef CONFIG_MACB_ZYNQ +/* INCR4 AHB bursts */ +#define MACB_ZYNQ_GEM_DMACR_BLENGTH 0x00000004 +/* Use full configured addressable space (8 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_RXSIZE 0x00000300 +/* Use full configured addressable space (4 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_TXSIZE 0x00000400 +/* Set RXBUF with use of 128 byte */ +#define MACB_ZYNQ_GEM_DMACR_RXBUF 0x00020000 +#define MACB_ZYNQ_GEM_DMACR_INIT \ + (MACB_ZYNQ_GEM_DMACR_BLENGTH | \ + MACB_ZYNQ_GEM_DMACR_RXSIZE | \ + MACB_ZYNQ_GEM_DMACR_TXSIZE | \ + MACB_ZYNQ_GEM_DMACR_RXBUF) +#endif + struct macb_dma_desc { u32 addr; u32 ctrl; @@ -461,13 +477,25 @@ static int macb_phy_find(struct macb_device *macb, const char *name) phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id != 0xffff) { printf("%s: PHY present at %d\n", name, i); - return 1; + return 0; } } /* PHY isn't up to snuff */ printf("%s: PHY not found\n", name); + return -ENODEV; +} + +/** + * macb_linkspd_cb - Linkspeed change callback function + * @regs: Base Register of MACB devices + * @speed: Linkspeed + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_linkspd_cb(void *regs, unsigned int speed) +{ return 0; } @@ -483,18 +511,20 @@ static int macb_phy_init(struct macb_device *macb, const char *name) u32 ncfgr; u16 phy_id, status, adv, lpa; int media, speed, duplex; + int ret; int i; arch_get_mdio_control(name); /* Auto-detect phy_addr */ - if (!macb_phy_find(macb, name)) - return 0; + ret = macb_phy_find(macb, name); + if (ret) + return ret; /* Check if the PHY is up to snuff... */ phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id == 0xffff) { printf("%s: No PHY present\n", name); - return 0; + return -ENODEV; } #ifdef CONFIG_PHYLIB @@ -530,7 +560,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) if (!(status & BMSR_LSTATUS)) { printf("%s: link down (status: 0x%04x)\n", name, status); - return 0; + return -ENETDOWN; } /* First check for GMAC and that it is GiB capable */ @@ -554,7 +584,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name) macb_writel(macb, NCFGR, ncfgr); - return 1; + ret = macb_linkspd_cb(macb->regs, _1000BASET); + if (ret) + return ret; + + return 0; } } @@ -573,13 +607,21 @@ static int macb_phy_init(struct macb_device *macb, const char *name) ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); - if (speed) + if (speed) { ncfgr |= MACB_BIT(SPD); + ret = macb_linkspd_cb(macb->regs, _100BASET); + } else { + ret = macb_linkspd_cb(macb->regs, _10BASET); + } + + if (ret) + return ret; + if (duplex) ncfgr |= MACB_BIT(FD); macb_writel(macb, NCFGR, ncfgr); - return 1; + return 0; } static int gmac_init_multi_queues(struct macb_device *macb) @@ -616,6 +658,7 @@ static int _macb_init(struct macb_device *macb, const char *name) struct macb_device *macb = dev_get_priv(dev); #endif unsigned long paddr; + int ret; int i; /* @@ -649,6 +692,10 @@ static int _macb_init(struct macb_device *macb, const char *name) macb->tx_tail = 0; macb->next_rx_tail = 0; +#ifdef CONFIG_MACB_ZYNQ + macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT); +#endif + macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); @@ -709,11 +756,12 @@ static int _macb_init(struct macb_device *macb, const char *name) } #ifdef CONFIG_DM_ETH - if (!macb_phy_init(dev, name)) + ret = macb_phy_init(dev, name); #else - if (!macb_phy_init(macb, name)) + ret = macb_phy_init(macb, name); #endif - return -1; + if (ret) + return ret; /* Enable TX and RX */ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); @@ -1013,9 +1061,15 @@ static int macb_enable_clk(struct udevice *dev) if (ret) return -EINVAL; + /* + * Zynq clock driver didn't support for enable or disable + * clock. Hence, clk_enable() didn't apply for Zynq + */ +#ifndef CONFIG_MACB_ZYNQ ret = clk_enable(&clk); if (ret) return ret; +#endif clk_rate = clk_get_rate(&clk); if (!clk_rate) @@ -1083,12 +1137,24 @@ static int macb_eth_remove(struct udevice *dev) return 0; } +/** + * macb_late_eth_ofdata_to_platdata + * @dev: udevice struct + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_late_eth_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + static int macb_eth_ofdata_to_platdata(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); pdata->iobase = devfdt_get_addr(dev); - return 0; + + return macb_late_eth_ofdata_to_platdata(dev); } static const struct udevice_id macb_eth_ids[] = { @@ -1097,6 +1163,7 @@ static const struct udevice_id macb_eth_ids[] = { { .compatible = "atmel,sama5d2-gem" }, { .compatible = "atmel,sama5d3-gem" }, { .compatible = "atmel,sama5d4-gem" }, + { .compatible = "cdns,zynq-gem" }, { } }; diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 5bb48f449c8..c39554df5fc 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -11,6 +11,7 @@ #define MACB_NCFGR 0x0004 #define MACB_NSR 0x0008 #define GEM_UR 0x000c +#define MACB_DMACFG 0x0010 #define MACB_TSR 0x0014 #define MACB_RBQP 0x0018 #define MACB_TBQP 0x001c diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index f1be9521a91..83e31537688 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1654,7 +1654,11 @@ static int mvneta_recv(struct udevice *dev, int flags, uchar **packetp) */ *packetp = data; - mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done); + /* + * Only mark one descriptor as free + * since only one was processed + */ + mvneta_rxq_desc_num_update(pp, rxq, 1, 1); } return rx_bytes; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e9dbedf3268..028fca96639 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -153,14 +153,17 @@ int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port, len = sizeof(input_buffer) - input_size; end = input_offset + input_size; - if (end > sizeof(input_buffer)) + if (end >= sizeof(input_buffer)) end -= sizeof(input_buffer); chunk = len; - if (end + len > sizeof(input_buffer)) { + /* Check if packet will wrap in input_buffer */ + if (end + len >= sizeof(input_buffer)) { chunk = sizeof(input_buffer) - end; + /* Copy the second part of the pkt to start of input_buffer */ memcpy(input_buffer, pkt + chunk, len - chunk); } + /* Copy first (or only) part of pkt after end of current valid input*/ memcpy(input_buffer + end, pkt, chunk); input_size += len; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index e32f1eb1c04..95b75343236 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -12,6 +12,23 @@ menuconfig PHYLIB if PHYLIB +config B53_SWITCH + bool "Broadcom BCM53xx (RoboSwitch) Ethernet switch PHY support." + help + Enable support for Broadcom BCM53xx (RoboSwitch) Ethernet switches. + This currently supports BCM53125 and similar models. + +if B53_SWITCH + +config B53_CPU_PORT + int "CPU port" + default 8 + +config B53_PHY_PORTS + hex "Bitmask of PHY ports" + +endif # B53_SWITCH + config MV88E61XX_SWITCH bool "Marvel MV88E61xx Ethernet switch PHY support." diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 1e264b2f2b0..f1980371c36 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -6,6 +6,7 @@ # obj-$(CONFIG_BITBANGMII) += miiphybb.o +obj-$(CONFIG_B53_SWITCH) += b53.o obj-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index b34cdd3d87d..d7e76deeb7c 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -19,6 +19,7 @@ static int ar8021_config(struct phy_device *phydev) { + phy_write(phydev, MDIO_DEVAD_NONE, 0x00, 0x1200); phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47); diff --git a/drivers/net/phy/b53.c b/drivers/net/phy/b53.c new file mode 100644 index 00000000000..f7f2d9f1eef --- /dev/null +++ b/drivers/net/phy/b53.c @@ -0,0 +1,768 @@ +/* + * Copyright (C) 2017 + * Broadcom + * Florian Fainelli <f.fainelli@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * PHY driver for Broadcom BCM53xx (roboswitch) Ethernet switches. + * + * This driver configures the b53 for basic use as a PHY. The switch supports + * vendor tags and VLAN configuration that can affect the switching decisions. + * This driver uses a simple configuration in which all ports are only allowed + * to send frames to the CPU port and receive frames from the CPU port this + * providing port isolation (no cross talk). + * + * The configuration determines which PHY ports to activate using the + * CONFIG_B53_PHY_PORTS bitmask. Set bit N will active port N and so on. + * + * This driver was written primarily for the Lamobo R1 platform using a BCM53152 + * switch but the BCM53xx being largely register compatible, extending it to + * cover other switches would be trivial. + */ + +#include <common.h> + +#include <errno.h> +#include <malloc.h> +#include <miiphy.h> +#include <netdev.h> + +/* Pseudo-PHY address (non configurable) to access internal registers */ +#define BRCM_PSEUDO_PHY_ADDR 30 + +/* Maximum number of ports possible */ +#define B53_N_PORTS 9 + +#define B53_CTRL_PAGE 0x00 /* Control */ +#define B53_MGMT_PAGE 0x02 /* Management Mode */ +/* Port VLAN Page */ +#define B53_PVLAN_PAGE 0x31 + +/* Control Page registers */ +#define B53_PORT_CTRL(i) (0x00 + (i)) +#define PORT_CTRL_RX_DISABLE BIT(0) +#define PORT_CTRL_TX_DISABLE BIT(1) +#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */ +#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */ +#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */ + +/* Switch Mode Control Register (8 bit) */ +#define B53_SWITCH_MODE 0x0b +#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */ +#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */ + +/* IMP Port state override register (8 bit) */ +#define B53_PORT_OVERRIDE_CTRL 0x0e +#define PORT_OVERRIDE_LINK BIT(0) +#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */ +#define PORT_OVERRIDE_SPEED_S 2 +#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S) +#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S) +/* BCM5325 only */ +#define PORT_OVERRIDE_RV_MII_25 BIT(4) +#define PORT_OVERRIDE_RX_FLOW BIT(4) +#define PORT_OVERRIDE_TX_FLOW BIT(5) +/* BCM5301X only, requires setting 1000M */ +#define PORT_OVERRIDE_SPEED_2000M BIT(6) +#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */ + +#define B53_RGMII_CTRL_IMP 0x60 +#define RGMII_CTRL_ENABLE_GMII BIT(7) +#define RGMII_CTRL_TIMING_SEL BIT(2) +#define RGMII_CTRL_DLL_RXC BIT(1) +#define RGMII_CTRL_DLL_TXC BIT(0) + +/* Switch control (8 bit) */ +#define B53_SWITCH_CTRL 0x22 +#define B53_MII_DUMB_FWDG_EN BIT(6) + +/* Software reset register (8 bit) */ +#define B53_SOFTRESET 0x79 +#define SW_RST BIT(7) +#define EN_CH_RST BIT(6) +#define EN_SW_RST BIT(4) + +/* Fast Aging Control register (8 bit) */ +#define B53_FAST_AGE_CTRL 0x88 +#define FAST_AGE_STATIC BIT(0) +#define FAST_AGE_DYNAMIC BIT(1) +#define FAST_AGE_PORT BIT(2) +#define FAST_AGE_VLAN BIT(3) +#define FAST_AGE_STP BIT(4) +#define FAST_AGE_MC BIT(5) +#define FAST_AGE_DONE BIT(7) + +/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */ +#define B53_PVLAN_PORT_MASK(i) ((i) * 2) + +/* MII registers */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +#define REG_MII_PAGE_ENABLE BIT(0) +#define REG_MII_ADDR_WRITE BIT(0) +#define REG_MII_ADDR_READ BIT(1) + +struct b53_device { + struct mii_dev *bus; + unsigned int cpu_port; +}; + +static int b53_mdio_op(struct mii_dev *bus, u8 page, u8 reg, u16 op) +{ + int ret; + int i; + u16 v; + + /* set page number */ + v = (page << 8) | REG_MII_PAGE_ENABLE; + ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_PAGE, v); + if (ret) + return ret; + + /* set register address */ + v = (reg << 8) | op; + ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_ADDR, v); + if (ret) + return ret; + + /* check if operation completed */ + for (i = 0; i < 5; ++i) { + v = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_ADDR); + if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ))) + break; + + udelay(100); + } + + if (i == 5) + return -EIO; + + return 0; +} + +static int b53_mdio_read8(struct mii_dev *bus, u8 page, u8 reg, u8 *val) +{ + int ret; + + ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0) & 0xff; + + return 0; +} + +static int b53_mdio_read16(struct mii_dev *bus, u8 page, u8 reg, u16 *val) +{ + int ret; + + ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0); + + return 0; +} + +static int b53_mdio_read32(struct mii_dev *bus, u8 page, u8 reg, u32 *val) +{ + int ret; + + ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + *val = bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0); + *val |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA1) << 16; + + return 0; +} + +static int b53_mdio_read48(struct mii_dev *bus, u8 page, u8 reg, u64 *val) +{ + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 2; i >= 0; i--) { + temp <<= 16; + temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_read64(struct mii_dev *bus, u8 page, u8 reg, u64 *val) +{ + u64 temp = 0; + int i; + int ret; + + ret = b53_mdio_op(bus, page, reg, REG_MII_ADDR_READ); + if (ret) + return ret; + + for (i = 3; i >= 0; i--) { + temp <<= 16; + temp |= bus->read(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0 + i); + } + + *val = temp; + + return 0; +} + +static int b53_mdio_write8(struct mii_dev *bus, u8 page, u8 reg, u8 value) +{ + int ret; + + ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write16(struct mii_dev *bus, u8 page, u8 reg, + u16 value) +{ + int ret; + + ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, MDIO_DEVAD_NONE, + REG_MII_DATA0, value); + if (ret) + return ret; + + return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write32(struct mii_dev *bus, u8 page, u8 reg, + u32 value) +{ + unsigned int i; + u32 temp = value; + + for (i = 0; i < 2; i++) { + int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, + MDIO_DEVAD_NONE, + REG_MII_DATA0 + i, temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write48(struct mii_dev *bus, u8 page, u8 reg, + u64 value) +{ + unsigned int i; + u64 temp = value; + + for (i = 0; i < 3; i++) { + int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, + MDIO_DEVAD_NONE, + REG_MII_DATA0 + i, temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE); +} + +static int b53_mdio_write64(struct mii_dev *bus, u8 page, u8 reg, + u64 value) +{ + unsigned int i; + u64 temp = value; + + for (i = 0; i < 4; i++) { + int ret = bus->write(bus, BRCM_PSEUDO_PHY_ADDR, + MDIO_DEVAD_NONE, + REG_MII_DATA0 + i, temp & 0xffff); + if (ret) + return ret; + temp >>= 16; + } + + return b53_mdio_op(bus, page, reg, REG_MII_ADDR_WRITE); +} + +static inline int b53_read8(struct b53_device *dev, u8 page, + u8 reg, u8 *value) +{ + return b53_mdio_read8(dev->bus, page, reg, value); +} + +static inline int b53_read16(struct b53_device *dev, u8 page, + u8 reg, u16 *value) +{ + return b53_mdio_read16(dev->bus, page, reg, value); +} + +static inline int b53_read32(struct b53_device *dev, u8 page, + u8 reg, u32 *value) +{ + return b53_mdio_read32(dev->bus, page, reg, value); +} + +static inline int b53_read48(struct b53_device *dev, u8 page, + u8 reg, u64 *value) +{ + return b53_mdio_read48(dev->bus, page, reg, value); +} + +static inline int b53_read64(struct b53_device *dev, u8 page, + u8 reg, u64 *value) +{ + return b53_mdio_read64(dev->bus, page, reg, value); +} + +static inline int b53_write8(struct b53_device *dev, u8 page, + u8 reg, u8 value) +{ + return b53_mdio_write8(dev->bus, page, reg, value); +} + +static inline int b53_write16(struct b53_device *dev, u8 page, + u8 reg, u16 value) +{ + return b53_mdio_write16(dev->bus, page, reg, value); +} + +static inline int b53_write32(struct b53_device *dev, u8 page, + u8 reg, u32 value) +{ + return b53_mdio_write32(dev->bus, page, reg, value); +} + +static inline int b53_write48(struct b53_device *dev, u8 page, + u8 reg, u64 value) +{ + return b53_mdio_write48(dev->bus, page, reg, value); +} + +static inline int b53_write64(struct b53_device *dev, u8 page, + u8 reg, u64 value) +{ + return b53_mdio_write64(dev->bus, page, reg, value); +} + +static int b53_flush_arl(struct b53_device *dev, u8 mask) +{ + unsigned int i; + + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + FAST_AGE_DONE | FAST_AGE_DYNAMIC | mask); + + for (i = 0; i < 10; i++) { + u8 fast_age_ctrl; + + b53_read8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, + &fast_age_ctrl); + + if (!(fast_age_ctrl & FAST_AGE_DONE)) + goto out; + + mdelay(1); + } + + return -ETIMEDOUT; +out: + /* Only age dynamic entries (default behavior) */ + b53_write8(dev, B53_CTRL_PAGE, B53_FAST_AGE_CTRL, FAST_AGE_DYNAMIC); + return 0; +} + +static int b53_switch_reset(struct phy_device *phydev) +{ + struct b53_device *dev = phydev->priv; + unsigned int timeout = 1000; + u8 mgmt; + u8 reg; + + b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, ®); + reg |= SW_RST | EN_SW_RST | EN_CH_RST; + b53_write8(dev, B53_CTRL_PAGE, B53_SOFTRESET, reg); + + do { + b53_read8(dev, B53_CTRL_PAGE, B53_SOFTRESET, ®); + if (!(reg & SW_RST)) + break; + + mdelay(1); + } while (timeout-- > 0); + + if (timeout == 0) + return -ETIMEDOUT; + + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + mgmt &= ~SM_SW_FWD_MODE; + mgmt |= SM_SW_FWD_EN; + + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt); + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, &mgmt); + + if (!(mgmt & SM_SW_FWD_EN)) { + printf("Failed to enable switch!\n"); + return -EINVAL; + } + } + + /* Include IMP port in dumb forwarding mode when no tagging protocol + * is configured + */ + b53_read8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, &mgmt); + mgmt |= B53_MII_DUMB_FWDG_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt); + + return b53_flush_arl(dev, FAST_AGE_STATIC); +} + +static void b53_enable_cpu_port(struct phy_device *phydev) +{ + struct b53_device *dev = phydev->priv; + u8 port_ctrl; + + port_ctrl = PORT_CTRL_RX_BCST_EN | + PORT_CTRL_RX_MCST_EN | + PORT_CTRL_RX_UCST_EN; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(dev->cpu_port), port_ctrl); + + port_ctrl = PORT_OVERRIDE_EN | PORT_OVERRIDE_LINK | + PORT_OVERRIDE_FULL_DUPLEX | PORT_OVERRIDE_SPEED_1000M; + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_OVERRIDE_CTRL, port_ctrl); + + b53_read8(dev, B53_CTRL_PAGE, B53_RGMII_CTRL_IMP, &port_ctrl); +} + +static void b53_imp_vlan_setup(struct b53_device *dev, int cpu_port) +{ + unsigned int port; + u16 pvlan; + + /* Enable the IMP port to be in the same VLAN as the other ports + * on a per-port basis such that we only have Port i and IMP in + * the same VLAN. + */ + for (port = 0; port < B53_N_PORTS; port++) { + if (!((1 << port) & CONFIG_B53_PHY_PORTS)) + continue; + + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), + &pvlan); + pvlan |= BIT(cpu_port); + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), + pvlan); + } +} + +static int b53_port_enable(struct phy_device *phydev, unsigned int port) +{ + struct b53_device *dev = phydev->priv; + unsigned int cpu_port = dev->cpu_port; + u16 pvlan; + + /* Clear the Rx and Tx disable bits and set to no spanning tree */ + b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(port), 0); + + /* Set this port, and only this one to be in the default VLAN */ + b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan); + pvlan &= ~0x1ff; + pvlan |= BIT(port); + b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); + + b53_imp_vlan_setup(dev, cpu_port); + + return 0; +} + +static int b53_switch_init(struct phy_device *phydev) +{ + static int init; + int ret; + + if (init) + return 0; + + ret = b53_switch_reset(phydev); + if (ret < 0) + return ret; + + b53_enable_cpu_port(phydev); + + init = 1; + + return 0; +} + +static int b53_probe(struct phy_device *phydev) +{ + struct b53_device *dev; + int ret; + + dev = malloc(sizeof(*dev)); + if (!dev) + return -ENOMEM; + + memset(dev, 0, sizeof(*dev)); + + phydev->priv = dev; + dev->bus = phydev->bus; + dev->cpu_port = CONFIG_B53_CPU_PORT; + + ret = b53_switch_reset(phydev); + if (ret < 0) + return ret; + + return 0; +} + +static int b53_phy_config(struct phy_device *phydev) +{ + unsigned int port; + int res; + + res = b53_switch_init(phydev); + if (res < 0) + return res; + + for (port = 0; port < B53_N_PORTS; port++) { + if (!((1 << port) & CONFIG_B53_PHY_PORTS)) + continue; + + res = b53_port_enable(phydev, port); + if (res < 0) { + printf("Error enabling port %i\n", port); + continue; + } + + res = genphy_config_aneg(phydev); + if (res < 0) { + printf("Error setting PHY %i autoneg\n", port); + continue; + } + + res = 0; + } + + return res; +} + +static int b53_phy_startup(struct phy_device *phydev) +{ + unsigned int port; + int res; + + for (port = 0; port < B53_N_PORTS; port++) { + if (!((1 << port) & CONFIG_B53_PHY_PORTS)) + continue; + + phydev->addr = port; + + res = genphy_startup(phydev); + if (res < 0) + continue; + else + break; + } + + /* Since we are connected directly to the switch, hardcode the link + * parameters to match those of the CPU port configured in + * b53_enable_cpu_port, we cannot be dependent on the user-facing port + * settings (e.g: 100Mbits/sec would not work here) + */ + phydev->speed = 1000; + phydev->duplex = 1; + phydev->link = 1; + + return 0; +} + +static struct phy_driver b53_driver = { + .name = "Broadcom BCM53125", + .uid = 0x03625c00, + .mask = 0xfffffc00, + .features = PHY_GBIT_FEATURES, + .probe = b53_probe, + .config = b53_phy_config, + .startup = b53_phy_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_b53_init(void) +{ + phy_register(&b53_driver); + + return 0; +} + +int do_b53_reg_read(const char *name, int argc, char * const argv[]) +{ + u8 page, offset, width; + struct mii_dev *bus; + int ret = -EINVAL; + u64 value64 = 0; + u32 value32 = 0; + u16 value16 = 0; + u8 value8 = 0; + + bus = miiphy_get_dev_by_name(name); + if (!bus) { + printf("unable to find MDIO bus: %s\n", name); + return ret; + } + + page = simple_strtoul(argv[1], NULL, 16); + offset = simple_strtoul(argv[2], NULL, 16); + width = simple_strtoul(argv[3], NULL, 10); + + switch (width) { + case 8: + ret = b53_mdio_read8(bus, page, offset, &value8); + printf("page=0x%02x, offset=0x%02x, value=0x%02x\n", + page, offset, value8); + break; + case 16: + ret = b53_mdio_read16(bus, page, offset, &value16); + printf("page=0x%02x, offset=0x%02x, value=0x%04x\n", + page, offset, value16); + break; + case 32: + ret = b53_mdio_read32(bus, page, offset, &value32); + printf("page=0x%02x, offset=0x%02x, value=0x%08x\n", + page, offset, value32); + break; + case 48: + ret = b53_mdio_read48(bus, page, offset, &value64); + printf("page=0x%02x, offset=0x%02x, value=0x%012llx\n", + page, offset, value64); + break; + case 64: + ret = b53_mdio_read48(bus, page, offset, &value64); + printf("page=0x%02x, offset=0x%02x, value=0x%016llx\n", + page, offset, value64); + break; + default: + printf("Unsupported width: %d\n", width); + break; + } + + return ret; +} + +int do_b53_reg_write(const char *name, int argc, char * const argv[]) +{ + u8 page, offset, width; + struct mii_dev *bus; + int ret = -EINVAL; + u64 value64 = 0; + u32 value = 0; + + bus = miiphy_get_dev_by_name(name); + if (!bus) { + printf("unable to find MDIO bus: %s\n", name); + return ret; + } + + page = simple_strtoul(argv[1], NULL, 16); + offset = simple_strtoul(argv[2], NULL, 16); + width = simple_strtoul(argv[3], NULL, 10); + if (width == 48 || width == 64) + value64 = simple_strtoull(argv[4], NULL, 16); + else + value = simple_strtoul(argv[4], NULL, 16); + + switch (width) { + case 8: + ret = b53_mdio_write8(bus, page, offset, value & 0xff); + break; + case 16: + ret = b53_mdio_write16(bus, page, offset, value); + break; + case 32: + ret = b53_mdio_write32(bus, page, offset, value); + break; + case 48: + ret = b53_mdio_write48(bus, page, offset, value64); + break; + case 64: + ret = b53_mdio_write64(bus, page, offset, value64); + break; + default: + printf("Unsupported width: %d\n", width); + break; + } + + return ret; +} + +int do_b53_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *cmd, *mdioname; + int ret = 0; + + if (argc < 2) + return cmd_usage(cmdtp); + + cmd = argv[1]; + --argc; + ++argv; + + if (!strcmp(cmd, "write")) { + if (argc < 4) + return cmd_usage(cmdtp); + mdioname = argv[1]; + --argc; + ++argv; + ret = do_b53_reg_write(mdioname, argc, argv); + } else if (!strcmp(cmd, "read")) { + if (argc < 5) + return cmd_usage(cmdtp); + mdioname = argv[1]; + --argc; + ++argv; + ret = do_b53_reg_read(mdioname, argc, argv); + } else { + return cmd_usage(cmdtp); + } + + return ret; +} + +U_BOOT_CMD(b53_reg, 7, 1, do_b53_reg, + "Broadcom B53 switch register access", + "write mdioname page (hex) offset (hex) width (dec) value (hex)\n" + "read mdioname page (hex) offset (hex) width (dec)\n" + ); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index b7f300e40f2..0b9a9fce8a5 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -104,6 +104,31 @@ #define MIIM_88E151x_MODE_SGMII 1 #define MIIM_88E151x_RESET_OFFS 15 +static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr, + int devaddr, int regnum) +{ + int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE); + int val; + + phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr); + val = phy_read(phydev, MDIO_DEVAD_NONE, regnum); + phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage); + + return val; +} + +static int m88e1xxx_phy_extwrite(struct phy_device *phydev, int addr, + int devaddr, int regnum, u16 val) +{ + int oldpage = phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, devaddr); + phy_write(phydev, MDIO_DEVAD_NONE, regnum, val); + phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, oldpage); + + return 0; +} + /* Marvell 88E1011S */ static int m88e1011s_config(struct phy_device *phydev) { @@ -669,6 +694,8 @@ static struct phy_driver M88E1510_driver = { .config = &m88e1510_config, .startup = &m88e1011s_startup, .shutdown = &genphy_shutdown, + .readext = &m88e1xxx_phy_extread, + .writeext = &m88e1xxx_phy_extwrite, }; /* @@ -684,6 +711,8 @@ static struct phy_driver M88E1518_driver = { .config = &m88e1518_config, .startup = &m88e1011s_startup, .shutdown = &genphy_shutdown, + .readext = &m88e1xxx_phy_extread, + .writeext = &m88e1xxx_phy_extwrite, }; static struct phy_driver M88E1310_driver = { diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c index af676b9baee..d61722490ea 100644 --- a/drivers/net/phy/miiphybb.c +++ b/drivers/net/phy/miiphybb.c @@ -232,7 +232,7 @@ static void miiphy_pre(struct bb_miiphy_bus *bus, char read, */ int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg) { - short rdreg; /* register working value */ + unsigned short rdreg; /* register working value */ int v; int j; /* counter */ struct bb_miiphy_bus *bus; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index fd3dd556c87..e31f3aa3a98 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -461,6 +461,9 @@ static LIST_HEAD(phy_drivers); int phy_init(void) { +#ifdef CONFIG_B53_SWITCH + phy_b53_init(); +#endif #ifdef CONFIG_MV88E61XX_SWITCH phy_mv88e61xx_init(); #endif diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 970d730e562..6edb51e12fa 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -29,7 +29,8 @@ #if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF) #define flush_cache_wback(addr, len) \ - flush_dcache_range((u32)addr, (u32)(addr + len - 1)) + flush_dcache_range((u32)addr, \ + (u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE))) #else #define flush_cache_wback(...) #endif @@ -67,7 +68,7 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len) /* packet must be a 4 byte boundary */ if ((int)packet & 3) { - printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n" + printf(SHETHER_NAME ": %s: packet not 4 byte aligned\n" , __func__); ret = -EFAULT; goto err; @@ -86,8 +87,8 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len) flush_cache_wback(port_info->tx_desc_cur, sizeof(struct tx_desc_s)); /* Restart the transmitter if disabled */ - if (!(sh_eth_read(eth, EDTRR) & EDTRR_TRNS)) - sh_eth_write(eth, EDTRR_TRNS, EDTRR); + if (!(sh_eth_read(port_info, EDTRR) & EDTRR_TRNS)) + sh_eth_write(port_info, EDTRR_TRNS, EDTRR); /* Wait until packet is transmitted */ timeout = TIMEOUT_CNT; @@ -147,24 +148,25 @@ int sh_eth_recv(struct eth_device *dev) } /* Restart the receiver if disabled */ - if (!(sh_eth_read(eth, EDRRR) & EDRRR_R)) - sh_eth_write(eth, EDRRR_R, EDRRR); + if (!(sh_eth_read(port_info, EDRRR) & EDRRR_R)) + sh_eth_write(port_info, EDRRR_R, EDRRR); return len; } static int sh_eth_reset(struct sh_eth_dev *eth) { + struct sh_eth_info *port_info = ð->port_info[eth->port]; #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) int ret = 0, i; /* Start e-dmac transmitter and receiver */ - sh_eth_write(eth, EDSR_ENALL, EDSR); + sh_eth_write(port_info, EDSR_ENALL, EDSR); /* Perform a software reset and wait for it to complete */ - sh_eth_write(eth, EDMR_SRST, EDMR); + sh_eth_write(port_info, EDMR_SRST, EDMR); for (i = 0; i < TIMEOUT_CNT; i++) { - if (!(sh_eth_read(eth, EDMR) & EDMR_SRST)) + if (!(sh_eth_read(port_info, EDMR) & EDMR_SRST)) break; udelay(1000); } @@ -176,9 +178,10 @@ static int sh_eth_reset(struct sh_eth_dev *eth) return ret; #else - sh_eth_write(eth, sh_eth_read(eth, EDMR) | EDMR_SRST, EDMR); + sh_eth_write(port_info, sh_eth_read(port_info, EDMR) | EDMR_SRST, EDMR); udelay(3000); - sh_eth_write(eth, sh_eth_read(eth, EDMR) & ~EDMR_SRST, EDMR); + sh_eth_write(port_info, + sh_eth_read(port_info, EDMR) & ~EDMR_SRST, EDMR); return 0; #endif @@ -203,7 +206,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) goto err; } - flush_cache_wback((u32)port_info->tx_desc_alloc, alloc_desc_size); + flush_cache_wback(port_info->tx_desc_alloc, alloc_desc_size); /* Make sure we use a P2 address (non-cacheable) */ port_info->tx_desc_base = @@ -222,13 +225,15 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) cur_tx_desc--; cur_tx_desc->td0 |= TD_TDLE; - /* Point the controller to the tx descriptor list. Must use physical - addresses */ - sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR); + /* + * Point the controller to the tx descriptor list. Must use physical + * addresses + */ + sh_eth_write(port_info, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR); #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) - sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR); - sh_eth_write(eth, ADDR_TO_PHY(cur_tx_desc), TDFXR); - sh_eth_write(eth, 0x01, TDFFR);/* Last discriptor bit */ + sh_eth_write(port_info, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR); + sh_eth_write(port_info, ADDR_TO_PHY(cur_tx_desc), TDFXR); + sh_eth_write(port_info, 0x01, TDFFR);/* Last discriptor bit */ #endif err: @@ -237,7 +242,7 @@ err: static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) { - int port = eth->port, i , ret = 0; + int port = eth->port, i, ret = 0; u32 alloc_desc_size = NUM_RX_DESC * sizeof(struct rx_desc_s); struct sh_eth_info *port_info = ð->port_info[port]; struct rx_desc_s *cur_rx_desc; @@ -283,7 +288,7 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) i < NUM_RX_DESC; cur_rx_desc++, rx_buf += MAX_BUF_SIZE, i++) { cur_rx_desc->rd0 = RD_RACT; cur_rx_desc->rd1 = MAX_BUF_SIZE << 16; - cur_rx_desc->rd2 = (u32) ADDR_TO_PHY(rx_buf); + cur_rx_desc->rd2 = (u32)ADDR_TO_PHY(rx_buf); } /* Mark the end of the descriptors */ @@ -291,11 +296,11 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) cur_rx_desc->rd0 |= RD_RDLE; /* Point the controller to the rx descriptor list */ - sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); + sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) - sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR); - sh_eth_write(eth, ADDR_TO_PHY(cur_rx_desc), RDFXR); - sh_eth_write(eth, RDFFR_RDLF, RDFFR); + sh_eth_write(port_info, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR); + sh_eth_write(port_info, ADDR_TO_PHY(cur_rx_desc), RDFXR); + sh_eth_write(port_info, RDFFR_RDLF, RDFFR); #endif return ret; @@ -371,7 +376,7 @@ static int sh_eth_phy_config(struct sh_eth_dev *eth) return ret; } -static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) +static int sh_eth_config(struct sh_eth_dev *eth) { int port = eth->port, ret = 0; u32 val; @@ -380,45 +385,45 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) struct phy_device *phy; /* Configure e-dmac registers */ - sh_eth_write(eth, (sh_eth_read(eth, EDMR) & ~EMDR_DESC_R) | + sh_eth_write(port_info, (sh_eth_read(port_info, EDMR) & ~EMDR_DESC_R) | (EMDR_DESC | EDMR_EL), EDMR); - sh_eth_write(eth, 0, EESIPR); - sh_eth_write(eth, 0, TRSCER); - sh_eth_write(eth, 0, TFTR); - sh_eth_write(eth, (FIFO_SIZE_T | FIFO_SIZE_R), FDR); - sh_eth_write(eth, RMCR_RST, RMCR); + sh_eth_write(port_info, 0, EESIPR); + sh_eth_write(port_info, 0, TRSCER); + sh_eth_write(port_info, 0, TFTR); + sh_eth_write(port_info, (FIFO_SIZE_T | FIFO_SIZE_R), FDR); + sh_eth_write(port_info, RMCR_RST, RMCR); #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) - sh_eth_write(eth, 0, RPADIR); + sh_eth_write(port_info, 0, RPADIR); #endif - sh_eth_write(eth, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR); + sh_eth_write(port_info, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR); /* Configure e-mac registers */ - sh_eth_write(eth, 0, ECSIPR); + sh_eth_write(port_info, 0, ECSIPR); /* Set Mac address */ val = dev->enetaddr[0] << 24 | dev->enetaddr[1] << 16 | dev->enetaddr[2] << 8 | dev->enetaddr[3]; - sh_eth_write(eth, val, MAHR); + sh_eth_write(port_info, val, MAHR); val = dev->enetaddr[4] << 8 | dev->enetaddr[5]; - sh_eth_write(eth, val, MALR); + sh_eth_write(port_info, val, MALR); - sh_eth_write(eth, RFLR_RFL_MIN, RFLR); + sh_eth_write(port_info, RFLR_RFL_MIN, RFLR); #if defined(SH_ETH_TYPE_GETHER) - sh_eth_write(eth, 0, PIPR); + sh_eth_write(port_info, 0, PIPR); #endif #if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) - sh_eth_write(eth, APR_AP, APR); - sh_eth_write(eth, MPR_MP, MPR); - sh_eth_write(eth, TPAUSER_TPAUSE, TPAUSER); + sh_eth_write(port_info, APR_AP, APR); + sh_eth_write(port_info, MPR_MP, MPR); + sh_eth_write(port_info, TPAUSER_TPAUSE, TPAUSER); #endif #if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740) - sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII); + sh_eth_write(port_info, CONFIG_SH_ETHER_SH7734_MII, RMII_MII); #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) - sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR); + sh_eth_write(port_info, sh_eth_read(port_info, RMIIMR) | 0x1, RMIIMR); #endif /* Configure phy */ ret = sh_eth_phy_config(eth); @@ -439,9 +444,9 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) if (phy->speed == 100) { printf(SHETHER_NAME ": 100Base/"); #if defined(SH_ETH_TYPE_GETHER) - sh_eth_write(eth, GECMR_100B, GECMR); + sh_eth_write(port_info, GECMR_100B, GECMR); #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) - sh_eth_write(eth, 1, RTRATE); + sh_eth_write(port_info, 1, RTRATE); #elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \ defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \ defined(CONFIG_R8A7794) @@ -450,26 +455,29 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) } else if (phy->speed == 10) { printf(SHETHER_NAME ": 10Base/"); #if defined(SH_ETH_TYPE_GETHER) - sh_eth_write(eth, GECMR_10B, GECMR); + sh_eth_write(port_info, GECMR_10B, GECMR); #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) - sh_eth_write(eth, 0, RTRATE); + sh_eth_write(port_info, 0, RTRATE); #endif } #if defined(SH_ETH_TYPE_GETHER) else if (phy->speed == 1000) { printf(SHETHER_NAME ": 1000Base/"); - sh_eth_write(eth, GECMR_1000B, GECMR); + sh_eth_write(port_info, GECMR_1000B, GECMR); } #endif /* Check if full duplex mode is supported by the phy */ if (phy->duplex) { printf("Full\n"); - sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE|ECMR_DM), + sh_eth_write(port_info, + val | (ECMR_CHG_DM | ECMR_RE | ECMR_TE | ECMR_DM), ECMR); } else { printf("Half\n"); - sh_eth_write(eth, val | (ECMR_CHG_DM|ECMR_RE|ECMR_TE), ECMR); + sh_eth_write(port_info, + val | (ECMR_CHG_DM | ECMR_RE | ECMR_TE), + ECMR); } return ret; @@ -480,16 +488,20 @@ err_phy_cfg: static void sh_eth_start(struct sh_eth_dev *eth) { + struct sh_eth_info *port_info = ð->port_info[eth->port]; + /* * Enable the e-dmac receiver only. The transmitter will be enabled when * we have something to transmit */ - sh_eth_write(eth, EDRRR_R, EDRRR); + sh_eth_write(port_info, EDRRR_R, EDRRR); } static void sh_eth_stop(struct sh_eth_dev *eth) { - sh_eth_write(eth, ~EDRRR_R, EDRRR); + struct sh_eth_info *port_info = ð->port_info[eth->port]; + + sh_eth_write(port_info, ~EDRRR_R, EDRRR); } int sh_eth_init(struct eth_device *dev, bd_t *bd) @@ -505,7 +517,7 @@ int sh_eth_init(struct eth_device *dev, bd_t *bd) if (ret) goto err; - ret = sh_eth_config(eth, bd); + ret = sh_eth_config(eth); if (ret) goto err_config; @@ -524,6 +536,7 @@ err: void sh_eth_halt(struct eth_device *dev) { struct sh_eth_dev *eth = dev->priv; + sh_eth_stop(eth); } @@ -532,6 +545,7 @@ int sh_eth_initialize(bd_t *bd) int ret = 0; struct sh_eth_dev *eth = NULL; struct eth_device *dev = NULL; + struct mii_dev *mdiodev; eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); if (!eth) { @@ -551,6 +565,8 @@ int sh_eth_initialize(bd_t *bd) eth->port = CONFIG_SH_ETHER_USE_PORT; eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; + eth->port_info[eth->port].iobase = + (void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port); dev->priv = (void *)eth; dev->iobase = 0; @@ -566,17 +582,16 @@ int sh_eth_initialize(bd_t *bd) eth_register(dev); bb_miiphy_buses[0].priv = eth; - int retval; - struct mii_dev *mdiodev = mdio_alloc(); + mdiodev = mdio_alloc(); if (!mdiodev) return -ENOMEM; strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); mdiodev->read = bb_miiphy_read; mdiodev->write = bb_miiphy_write; - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; + ret = mdio_register(mdiodev); + if (ret < 0) + return ret; if (!eth_env_get_enetaddr("ethaddr", dev->enetaddr)) puts("Please set MAC address\n"); @@ -603,8 +618,9 @@ static int sh_eth_bb_init(struct bb_miiphy_bus *bus) static int sh_eth_bb_mdio_active(struct bb_miiphy_bus *bus) { struct sh_eth_dev *eth = bus->priv; + struct sh_eth_info *port_info = ð->port_info[eth->port]; - sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MMD, PIR); + sh_eth_write(port_info, sh_eth_read(port_info, PIR) | PIR_MMD, PIR); return 0; } @@ -612,8 +628,9 @@ static int sh_eth_bb_mdio_active(struct bb_miiphy_bus *bus) static int sh_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus) { struct sh_eth_dev *eth = bus->priv; + struct sh_eth_info *port_info = ð->port_info[eth->port]; - sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MMD, PIR); + sh_eth_write(port_info, sh_eth_read(port_info, PIR) & ~PIR_MMD, PIR); return 0; } @@ -621,11 +638,14 @@ static int sh_eth_bb_mdio_tristate(struct bb_miiphy_bus *bus) static int sh_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v) { struct sh_eth_dev *eth = bus->priv; + struct sh_eth_info *port_info = ð->port_info[eth->port]; if (v) - sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDO, PIR); + sh_eth_write(port_info, + sh_eth_read(port_info, PIR) | PIR_MDO, PIR); else - sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDO, PIR); + sh_eth_write(port_info, + sh_eth_read(port_info, PIR) & ~PIR_MDO, PIR); return 0; } @@ -633,8 +653,9 @@ static int sh_eth_bb_set_mdio(struct bb_miiphy_bus *bus, int v) static int sh_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v) { struct sh_eth_dev *eth = bus->priv; + struct sh_eth_info *port_info = ð->port_info[eth->port]; - *v = (sh_eth_read(eth, PIR) & PIR_MDI) >> 3; + *v = (sh_eth_read(port_info, PIR) & PIR_MDI) >> 3; return 0; } @@ -642,11 +663,14 @@ static int sh_eth_bb_get_mdio(struct bb_miiphy_bus *bus, int *v) static int sh_eth_bb_set_mdc(struct bb_miiphy_bus *bus, int v) { struct sh_eth_dev *eth = bus->priv; + struct sh_eth_info *port_info = ð->port_info[eth->port]; if (v) - sh_eth_write(eth, sh_eth_read(eth, PIR) | PIR_MDC, PIR); + sh_eth_write(port_info, + sh_eth_read(port_info, PIR) | PIR_MDC, PIR); else - sh_eth_write(eth, sh_eth_read(eth, PIR) & ~PIR_MDC, PIR); + sh_eth_write(port_info, + sh_eth_read(port_info, PIR) & ~PIR_MDC, PIR); return 0; } @@ -670,4 +694,5 @@ struct bb_miiphy_bus bb_miiphy_buses[] = { .delay = sh_eth_bb_delay, } }; + int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 3645f0eca7c..a0dcfcae090 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -25,8 +25,10 @@ #define ADDR_TO_PHY(addr) ((int)(addr) & ~0xe0000000) #endif #elif defined(CONFIG_ARM) -#define inl readl +#ifndef inl +#define inl readl #define outl writel +#endif #define ADDR_TO_PHY(addr) ((int)(addr)) #define ADDR_TO_P2(addr) (addr) #endif /* defined(CONFIG_SH) */ @@ -90,6 +92,7 @@ struct sh_eth_info { u8 phy_addr; struct eth_device *dev; struct phy_device *phydev; + void __iomem *iobase; }; struct sh_eth_dev { @@ -226,61 +229,6 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [RMII_MII] = 0x0790, }; -#if defined(SH_ETH_TYPE_RZ) -static const u16 sh_eth_offset_rz[SH_ETH_MAX_REGISTER_OFFSET] = { - [EDSR] = 0x0000, - [EDMR] = 0x0400, - [EDTRR] = 0x0408, - [EDRRR] = 0x0410, - [EESR] = 0x0428, - [EESIPR] = 0x0430, - [TDLAR] = 0x0010, - [TDFAR] = 0x0014, - [TDFXR] = 0x0018, - [TDFFR] = 0x001c, - [RDLAR] = 0x0030, - [RDFAR] = 0x0034, - [RDFXR] = 0x0038, - [RDFFR] = 0x003c, - [TRSCER] = 0x0438, - [RMFCR] = 0x0440, - [TFTR] = 0x0448, - [FDR] = 0x0450, - [RMCR] = 0x0458, - [RPADIR] = 0x0460, - [FCFTR] = 0x0468, - [CSMR] = 0x04E4, - - [ECMR] = 0x0500, - [ECSR] = 0x0510, - [ECSIPR] = 0x0518, - [PSR] = 0x0528, - [PIPR] = 0x052c, - [RFLR] = 0x0508, - [APR] = 0x0554, - [MPR] = 0x0558, - [PFTCR] = 0x055c, - [PFRCR] = 0x0560, - [TPAUSER] = 0x0564, - [GECMR] = 0x05b0, - [BCULR] = 0x05b4, - [MAHR] = 0x05c0, - [MALR] = 0x05c8, - [TROCR] = 0x0700, - [CDCR] = 0x0708, - [LCCR] = 0x0710, - [CEFCR] = 0x0740, - [FRECR] = 0x0748, - [TSFRCR] = 0x0750, - [TLFRCR] = 0x0758, - [RFCR] = 0x0760, - [CERCR] = 0x0768, - [CEECR] = 0x0770, - [MAFCR] = 0x0778, - [RMII_MII] = 0x0790, -}; -#endif - static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { [ECMR] = 0x0100, [RFLR] = 0x0108, @@ -654,29 +602,27 @@ enum FIFO_SIZE_BIT { FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007, }; -static inline unsigned long sh_eth_reg_addr(struct sh_eth_dev *eth, +static inline unsigned long sh_eth_reg_addr(struct sh_eth_info *port, int enum_index) { -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) const u16 *reg_offset = sh_eth_offset_gigabit; #elif defined(SH_ETH_TYPE_ETHER) const u16 *reg_offset = sh_eth_offset_fast_sh4; -#elif defined(SH_ETH_TYPE_RZ) - const u16 *reg_offset = sh_eth_offset_rz; #else #error #endif - return BASE_IO_ADDR + reg_offset[enum_index] + 0x800 * eth->port; + return (unsigned long)port->iobase + reg_offset[enum_index]; } -static inline void sh_eth_write(struct sh_eth_dev *eth, unsigned long data, +static inline void sh_eth_write(struct sh_eth_info *port, unsigned long data, int enum_index) { - outl(data, sh_eth_reg_addr(eth, enum_index)); + outl(data, sh_eth_reg_addr(port, enum_index)); } -static inline unsigned long sh_eth_read(struct sh_eth_dev *eth, +static inline unsigned long sh_eth_read(struct sh_eth_info *port, int enum_index) { - return inl(sh_eth_reg_addr(eth, enum_index)); + return inl(sh_eth_reg_addr(port, enum_index)); } |