diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 8 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 2 | ||||
-rw-r--r-- | drivers/net/fm/fm.c | 2 | ||||
-rw-r--r-- | drivers/net/gmac_rockchip.c | 18 | ||||
-rw-r--r-- | drivers/net/ldpaa_eth/ldpaa_eth.c | 1 | ||||
-rw-r--r-- | drivers/net/macb.c | 57 | ||||
-rw-r--r-- | drivers/net/mscc_eswitch/Kconfig | 7 | ||||
-rw-r--r-- | drivers/net/mscc_eswitch/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/mscc_eswitch/luton_switch.c | 415 | ||||
-rw-r--r-- | drivers/net/mscc_eswitch/ocelot_switch.c | 434 | ||||
-rw-r--r-- | drivers/net/mscc_eswitch/serval_switch.c | 703 | ||||
-rw-r--r-- | drivers/net/mtk_eth.c | 7 | ||||
-rw-r--r-- | drivers/net/phy/Kconfig | 39 | ||||
-rw-r--r-- | drivers/net/phy/aquantia.c | 7 | ||||
-rw-r--r-- | drivers/net/phy/micrel_ksz8xxx.c | 8 | ||||
-rw-r--r-- | drivers/net/phy/micrel_ksz90x1.c | 26 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 21 | ||||
-rw-r--r-- | drivers/net/phy/realtek.c | 19 | ||||
-rw-r--r-- | drivers/net/phy/ti.c | 138 | ||||
-rw-r--r-- | drivers/net/ravb.c | 13 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 21 | ||||
-rw-r--r-- | drivers/net/sh_eth.c | 14 | ||||
-rw-r--r-- | drivers/net/sh_eth.h | 59 | ||||
-rw-r--r-- | drivers/net/sun8i_emac.c | 74 | ||||
-rw-r--r-- | drivers/net/ti/davinci_emac.c | 55 |
25 files changed, 1670 insertions, 483 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6e436b56abf..e6a4fdf30e7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -195,6 +195,12 @@ config FEC_MXC This driver supports the 10/100 Fast Ethernet controller for NXP i.MX processors. +config FMAN_ENET + bool "Freescale FMan ethernet support" + depends on ARM || PPC + help + This driver support the Freescale FMan Ethernet controller + config FTMAC100 bool "Ftmac100 Ethernet Support" help @@ -269,7 +275,7 @@ config MACB_ZYNQ config MT7628_ETH bool "MediaTek MT7628 Ethernet Interface" - depends on ARCH_MT7620 + depends on SOC_MT7628 help The MediaTek MT7628 ethernet interface is used on MT7628 and MT7688 based boards. diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9f1c5af46e9..590e756f5c6 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -241,7 +241,7 @@ struct eqos_tegra186_regs { */ #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning Cache line size is larger than descriptor size #endif #endif diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index e19d7777dcb..0a43dfe74e9 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -459,7 +459,7 @@ int fm_init_common(int index, struct ccsr_fman *reg) printf("NAND read of FMAN firmware at offset 0x%x failed %d\n", CONFIG_SYS_FMAN_FW_ADDR, rc); } -#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH) +#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_SPIFLASH) struct spi_flash *ucode_flash; void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); int ret = 0; diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c index c01ae758c76..26a61211750 100644 --- a/drivers/net/gmac_rockchip.c +++ b/drivers/net/gmac_rockchip.c @@ -11,15 +11,15 @@ #include <phy.h> #include <syscon.h> #include <asm/io.h> -#include <asm/arch/periph.h> -#include <asm/arch/clock.h> -#include <asm/arch/hardware.h> -#include <asm/arch/grf_rk322x.h> -#include <asm/arch/grf_rk3288.h> -#include <asm/arch/grf_rk3328.h> -#include <asm/arch/grf_rk3368.h> -#include <asm/arch/grf_rk3399.h> -#include <asm/arch/grf_rv1108.h> +#include <asm/arch-rockchip/periph.h> +#include <asm/arch-rockchip/clock.h> +#include <asm/arch-rockchip/hardware.h> +#include <asm/arch-rockchip/grf_rk322x.h> +#include <asm/arch-rockchip/grf_rk3288.h> +#include <asm/arch-rockchip/grf_rk3328.h> +#include <asm/arch-rockchip/grf_rk3368.h> +#include <asm/arch-rockchip/grf_rk3399.h> +#include <asm/arch-rockchip/grf_rv1108.h> #include <dm/pinctrl.h> #include <dt-bindings/clock/rk3288-cru.h> #include "designware.h" diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 73b7ba29dfd..34253e39249 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -1074,6 +1074,7 @@ int ldpaa_eth_init(int dpmac_id, phy_interface_t enet_if) priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv)); if (!priv) { printf("ldpaa_eth_priv malloc() failed\n"); + free(net_dev); return -ENOMEM; } memset(priv, 0, sizeof(struct ldpaa_eth_priv)); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 72614164e9c..c5560a71114 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -488,15 +488,58 @@ static int macb_phy_find(struct macb_device *macb, const char *name) /** * macb_linkspd_cb - Linkspeed change callback function - * @regs: Base Register of MACB devices + * @dev/@regs: MACB udevice (DM version) or + * Base Register of MACB devices (non-DM version) * @speed: Linkspeed * Returns 0 when operation success and negative errno number * when operation failed. */ +#ifdef CONFIG_DM_ETH +int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed) +{ +#ifdef CONFIG_CLK + struct clk tx_clk; + ulong rate; + int ret; + + /* + * "tx_clk" is an optional clock source for MACB. + * Ignore if it does not exist in DT. + */ + ret = clk_get_by_name(dev, "tx_clk", &tx_clk); + if (ret) + return 0; + + switch (speed) { + case _10BASET: + rate = 2500000; /* 2.5 MHz */ + break; + case _100BASET: + rate = 25000000; /* 25 MHz */ + break; + case _1000BASET: + rate = 125000000; /* 125 MHz */ + break; + default: + /* does not change anything */ + return 0; + } + + if (tx_clk.dev) { + ret = clk_set_rate(&tx_clk, rate); + if (ret) + return ret; + } +#endif + + return 0; +} +#else int __weak macb_linkspd_cb(void *regs, unsigned int speed) { return 0; } +#endif #ifdef CONFIG_DM_ETH static int macb_phy_init(struct udevice *dev, const char *name) @@ -589,7 +632,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name) macb_writel(macb, NCFGR, ncfgr); +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _1000BASET); +#else ret = macb_linkspd_cb(macb->regs, _1000BASET); +#endif if (ret) return ret; @@ -614,9 +661,17 @@ static int macb_phy_init(struct macb_device *macb, const char *name) ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); if (speed) { ncfgr |= MACB_BIT(SPD); +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _100BASET); +#else ret = macb_linkspd_cb(macb->regs, _100BASET); +#endif } else { +#ifdef CONFIG_DM_ETH + ret = macb_linkspd_cb(dev, _10BASET); +#else ret = macb_linkspd_cb(macb->regs, _10BASET); +#endif } if (ret) diff --git a/drivers/net/mscc_eswitch/Kconfig b/drivers/net/mscc_eswitch/Kconfig index 6359d0b6101..80dd22f98b7 100644 --- a/drivers/net/mscc_eswitch/Kconfig +++ b/drivers/net/mscc_eswitch/Kconfig @@ -29,3 +29,10 @@ config MSCC_SERVALT_SWITCH select PHYLIB help This driver supports the Servalt network switch device. + +config MSCC_SERVAL_SWITCH + bool "Serval switch driver" + depends on DM_ETH && ARCH_MSCC + select PHYLIB + help + This driver supports the Serval network switch device. diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile index bffd8ec77b0..02f39a76bb0 100644 --- a/drivers/net/mscc_eswitch/Makefile +++ b/drivers/net/mscc_eswitch/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o -obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o +obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o +obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o +obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c index 6667614966d..94852b06e74 100644 --- a/drivers/net/mscc_eswitch/luton_switch.c +++ b/drivers/net/mscc_eswitch/luton_switch.c @@ -15,10 +15,21 @@ #include <net.h> #include <wait_bit.h> -#include "mscc_miim.h" #include "mscc_xfer.h" #include "mscc_mac_table.h" +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x2 << 16) + #define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) @@ -136,61 +147,53 @@ #define PGID_UNICAST 29 #define PGID_SRC 80 -enum luton_target { - PORT0, - PORT1, - PORT2, - PORT3, - PORT4, - PORT5, - PORT6, - PORT7, - PORT8, - PORT9, - PORT10, - PORT11, - PORT12, - PORT13, - PORT14, - PORT15, - PORT16, - PORT17, - PORT18, - PORT19, - PORT20, - PORT21, - PORT22, - PORT23, - SYS, +static const char * const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7", + "port8", "port9", "port10", "port11", "port12", "port13", "port14", + "port15", "port16", "port17", "port18", "port19", "port20", "port21", + "port22", "port23", + "sys", "ana", "rew", "gcb", "qs", "hsio", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 24 + +enum luton_ctrl_regs { + SYS = MAX_PORT, ANA, REW, GCB, QS, - HSIO, - TARGET_MAX, + HSIO }; -#define MAX_PORT (PORT23 - PORT0 + 1) +#define MIN_INT_PORT 0 +#define PORT10 10 +#define PORT11 11 +#define MAX_INT_PORT 12 +#define MIN_EXT_PORT MAX_INT_PORT +#define MAX_EXT_PORT MAX_PORT -#define MIN_INT_PORT PORT0 -#define MAX_INT_PORT (PORT11 - PORT0 + 1) -#define MIN_EXT_PORT PORT12 -#define MAX_EXT_PORT MAX_PORT +#define LUTON_MIIM_BUS_COUNT 2 -enum luton_mdio_target { - MIIM, - TARGET_MDIO_MAX, +struct luton_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; }; -enum luton_phy_id { - INTERNAL, - EXTERNAL, - NUM_PHY, +struct luton_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[LUTON_MIIM_BUS_COUNT]; + struct luton_phy_port_t ports[MAX_PORT]; }; -struct luton_private { - void __iomem *regs[TARGET_MAX]; - struct mii_dev *bus[NUM_PHY]; +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; }; static const unsigned long luton_regs_qs[] = { @@ -207,53 +210,85 @@ static const unsigned long luton_regs_ana_table[] = { [MSCC_ANA_TABLES_MACACCESS] = 0x11b8, }; -static struct mscc_miim_dev miim[NUM_PHY]; +static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT]; +static int miim_count = -1; -static struct mii_dev *luton_mdiobus_init(struct udevice *dev, - int mdiobus_id) +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) { - unsigned long phy_size[NUM_PHY]; - phys_addr_t phy_base[NUM_PHY]; - struct ofnode_phandle_args phandle; - ofnode eth_node, node, mdio_node; - struct resource res; struct mii_dev *bus; - fdt32_t faddr; - int i; bus = mdio_alloc(); if (!bus) return NULL; - /* gather only the first mdio bus */ - eth_node = dev_read_first_subnode(dev); - node = ofnode_first_subnode(eth_node); - ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, - &phandle); - mdio_node = ofnode_get_parent(phandle.node); - - for (i = 0; i < TARGET_MDIO_MAX; i++) { - if (ofnode_read_resource(mdio_node, i, &res)) { - pr_err("%s: get OF resource failed\n", __func__); - return NULL; - } - - faddr = cpu_to_fdt32(res.start); - phy_base[i] = ofnode_translate_address(mdio_node, &faddr); - phy_size[i] = res.end - res.start; - } + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); - strcpy(bus->name, "miim-internal"); - miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id], - phy_size[mdiobus_id]); - bus->priv = &miim[mdiobus_id]; + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; bus->read = mscc_miim_read; bus->write = mscc_miim_write; if (mdio_register(bus)) return NULL; - else - return bus; + + miim[miim_count].bus = bus; + return bus; } static void luton_stop(struct udevice *dev) @@ -324,10 +359,10 @@ static void luton_gmii_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } @@ -346,10 +381,10 @@ static void luton_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } @@ -393,35 +428,34 @@ static void luton_ext_port_init(struct luton_private *priv, int port) writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | MAC_VID, - priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable switching to/from port */ - setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port), SYS_SWITCH_PORT_MODE_PORT_ENA); } -static void serdes6g_write(struct luton_private *priv, u32 addr) +static void serdes6g_write(void __iomem *base, u32 addr) { u32 data; writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT | HSIO_MCB_SERDES6G_CFG_ADDR(addr), - priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); + base + HSIO_MCB_SERDES6G_CFG); do { - data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG); + data = readl(base + HSIO_MCB_SERDES6G_CFG); } while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT); - - mdelay(100); } -static void serdes6g_cfg(struct luton_private *priv) +static void serdes6g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) { writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) | HSIO_RCOMP_CFG_CFG0_RUN_CAL, - priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0); + base + HSIO_RCOMP_CFG_CFG0); - while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) & + while (readl(base + HSIO_RCOMP_STATUS) & HSIO_RCOMP_STATUS_BUSY) ; @@ -430,50 +464,64 @@ static void serdes6g_cfg(struct luton_private *priv) HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) | HSIO_SERDES6G_ANA_CFG_OB_CFG_POL | HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG); + base + HSIO_SERDES6G_ANA_CFG_OB_CFG); writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) | HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1); + base + HSIO_SERDES6G_ANA_CFG_OB_CFG1); writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) | HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) | HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) | HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG); + base + HSIO_SERDES6G_ANA_CFG_IB_CFG); writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC | HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE | HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF | HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1); + base + HSIO_SERDES6G_ANA_CFG_IB_CFG1); writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) | HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) | HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) | HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG); + base + HSIO_SERDES6G_ANA_CFG_DES_CFG); writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA | HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78), - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG); + base + HSIO_SERDES6G_ANA_CFG_PLL_CFG); writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); + base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); /* * There are 4 serdes6g, configure all except serdes6g0, therefore * the address is b1110 */ - serdes6g_write(priv, 0xe); + serdes6g_write(base, addr); - writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | + writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) | HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST, - priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); - serdes6g_write(priv, 0xe); + base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG); + serdes6g_write(base, addr); - clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1, + clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1, HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST); writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST, - priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG); - serdes6g_write(priv, 0xe); + base + HSIO_SERDES6G_DIG_CFG_MISC_CFG); + serdes6g_write(base, addr); +} + +static void serdes_setup(struct luton_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode); + } } static int luton_switch_init(struct luton_private *priv) @@ -495,8 +543,8 @@ static int luton_switch_init(struct luton_private *priv) setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, SYS_SYSTEM_RST_CORE_ENA); - /* Setup the Serdes6g macros */ - serdes6g_cfg(priv); + /* Setup the Serdes macros */ + serdes_setup(priv); return 0; } @@ -525,7 +573,7 @@ static int luton_initialize(struct luton_private *priv) writel(2000000000 / 4, priv->regs[SYS] + SYS_FRM_AGING); - for (i = PORT0; i < MAX_PORT; i++) { + for (i = 0; i < MAX_PORT; i++) { if (i < PORT10) luton_gmii_port_init(priv, i); else @@ -608,56 +656,51 @@ static int luton_recv(struct udevice *dev, int flags, uchar **packetp) return byte_cnt; } +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct luton_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + static int luton_probe(struct udevice *dev) { struct luton_private *priv = dev_get_priv(dev); - int i; - - struct { - enum luton_target id; - char *name; - } reg[] = { - { PORT0, "port0" }, - { PORT1, "port1" }, - { PORT2, "port2" }, - { PORT3, "port3" }, - { PORT4, "port4" }, - { PORT5, "port5" }, - { PORT6, "port6" }, - { PORT7, "port7" }, - { PORT8, "port8" }, - { PORT9, "port9" }, - { PORT10, "port10" }, - { PORT11, "port11" }, - { PORT12, "port12" }, - { PORT13, "port13" }, - { PORT14, "port14" }, - { PORT15, "port15" }, - { PORT16, "port16" }, - { PORT17, "port17" }, - { PORT18, "port18" }, - { PORT19, "port19" }, - { PORT20, "port20" }, - { PORT21, "port21" }, - { PORT22, "port22" }, - { PORT23, "port23" }, - { SYS, "sys" }, - { ANA, "ana" }, - { REW, "rew" }, - { GCB, "gcb" }, - { QS, "qs" }, - { HSIO, "hsio" }, - }; + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; if (!priv) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(reg); i++) { - priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); - if (!priv->regs[reg[i].id]) { + /* Get registers and map them to the private structure */ + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { debug ("Error can't get regs base addresses for %s\n", - reg[i].name); + regs_names[i]); return -ENOMEM; } } @@ -666,7 +709,7 @@ static int luton_probe(struct udevice *dev) writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST); /* Ports with ext phy don't need to reset clk */ - for (i = PORT0; i < MAX_INT_PORT; i++) { + for (i = 0; i < MAX_INT_PORT; i++) { if (i < PORT10) clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK, DEV_GMII_PORT_MODE_CLK_PHY_RST); @@ -680,20 +723,76 @@ static int luton_probe(struct udevice *dev) GCB_MISC_STAT_PHY_READY, true, 500, false)) return -EACCES; - priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL); - for (i = 0; i < MAX_INT_PORT; i++) { - phy_connect(priv->bus[INTERNAL], i, dev, - PHY_INTERFACE_MODE_NONE); + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL, + 0, 0, &phandle); + if (ret) + continue; + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + serval_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff); + else + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy && i >= MAX_INT_PORT) + board_phy_config(phy); } /* * coma_mode is need on only one phy, because all the other phys * will be affected. */ - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10); - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800); - mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0); + mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10); + mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800); + mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0); return 0; } @@ -703,7 +802,7 @@ static int luton_remove(struct udevice *dev) struct luton_private *priv = dev_get_priv(dev); int i; - for (i = 0; i < NUM_PHY; i++) { + for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) { mdio_unregister(priv->bus[i]); mdio_free(priv->bus[i]); } diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c index 815c2da2646..5c7e6961be4 100644 --- a/drivers/net/mscc_eswitch/ocelot_switch.c +++ b/drivers/net/mscc_eswitch/ocelot_switch.c @@ -15,7 +15,6 @@ #include <net.h> #include <wait_bit.h> -#include "mscc_miim.h" #include "mscc_xfer.h" #include "mscc_mac_table.h" @@ -26,6 +25,20 @@ #define PHY_STAT 0x4 #define PHY_STAT_SUPERVISOR_COMPLETE BIT(0) +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_SCAN BIT(0) +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x3 << 16) + #define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) @@ -33,6 +46,41 @@ #define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) #define ANA_PGID(x) (0x8c00 + 4 * (x)) +#define HSIO_ANA_SERDES1G_DES_CFG 0x4c +#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1) +#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5) +#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_IB_CFG 0x50 +#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13) +#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24) +#define HSIO_ANA_SERDES1G_OB_CFG 0x54 +#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4) +#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10) +#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17) +#define HSIO_ANA_SERDES1G_SER_CFG 0x58 +#define HSIO_ANA_SERDES1G_COMMON_CFG 0x5c +#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0) +#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18) +#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31) +#define HSIO_ANA_SERDES1G_PLL_CFG 0x60 +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7) +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21) +#define HSIO_DIG_SERDES1G_DFT_CFG0 0x68 +#define HSIO_DIG_SERDES1G_MISC_CFG 0x7c +#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0) +#define HSIO_MCB_SERDES1G_CFG 0x88 +#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31) +#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x) +#define HSIO_HW_CFGSTAT_HW_CFG 0x10c + #define SYS_FRM_AGING 0x574 #define SYS_FRM_AGING_ENA BIT(20) @@ -83,49 +131,58 @@ #define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) #define IFH_INJ_BYPASS BIT(31) -#define IFH_TAG_TYPE_C 0 -#define MAC_VID 1 +#define IFH_TAG_TYPE_C 0 +#define MAC_VID 1 #define CPU_PORT 11 -#define INTERNAL_PORT_MSK 0xF +#define INTERNAL_PORT_MSK 0x2FF #define IFH_LEN 4 #define ETH_ALEN 6 -#define PGID_BROADCAST 13 -#define PGID_UNICAST 14 -#define PGID_SRC 80 +#define PGID_BROADCAST 13 +#define PGID_UNICAST 14 +#define PGID_SRC 80 -enum ocelot_target { - ANA, - QS, - QSYS, +static const char * const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7", + "port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 11 + +enum ocelot_ctrl_regs { + SYS = MAX_PORT, REW, - SYS, + QS, HSIO, - PORT0, - PORT1, - PORT2, - PORT3, - TARGET_MAX, + QSYS, + ANA, }; -#define MAX_PORT (PORT3 - PORT0) +#define OCELOT_MIIM_BUS_COUNT 2 -enum ocelot_mdio_target { - MIIM, - PHY, - TARGET_MDIO_MAX, +struct ocelot_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; }; -enum ocelot_phy_id { - INTERNAL, - EXTERNAL, - NUM_PHY, +struct ocelot_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT]; + struct ocelot_phy_port_t ports[MAX_PORT]; }; -struct ocelot_private { - void __iomem *regs[TARGET_MAX]; - struct mii_dev *bus[NUM_PHY]; +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; }; +static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT]; +static int miim_count = -1; + static const unsigned long ocelot_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_FLUSH] = 0x18, @@ -140,65 +197,95 @@ static const unsigned long ocelot_regs_ana_table[] = { [MSCC_ANA_TABLES_MACACCESS] = 0x8b3c, }; -static struct mscc_miim_dev miim[NUM_PHY]; - static void mscc_phy_reset(void) { - writel(0, miim[INTERNAL].phy_regs + PHY_CFG); + writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG); writel(PHY_CFG_RST | PHY_CFG_COMMON_RST - | PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG); - if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT, - PHY_STAT_SUPERVISOR_COMPLETE, + | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG); + if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) + + PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE, true, 2000, false)) { pr_err("Timeout in phy reset\n"); } } -/* For now only setup the internal mdio bus */ -static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev) +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) { - unsigned long phy_size[TARGET_MAX]; - phys_addr_t phy_base[TARGET_MAX]; - struct ofnode_phandle_args phandle; - ofnode eth_node, node, mdio_node; - struct resource res; struct mii_dev *bus; - fdt32_t faddr; - int i; bus = mdio_alloc(); if (!bus) return NULL; - /* gathered only the first mdio bus */ - eth_node = dev_read_first_subnode(dev); - node = ofnode_first_subnode(eth_node); - ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, - &phandle); - mdio_node = ofnode_get_parent(phandle.node); - - for (i = 0; i < TARGET_MDIO_MAX; i++) { - if (ofnode_read_resource(mdio_node, i, &res)) { - pr_err("%s: get OF resource failed\n", __func__); - return NULL; - } - faddr = cpu_to_fdt32(res.start); - phy_base[i] = ofnode_translate_address(mdio_node, &faddr); - phy_size[i] = res.end - res.start; - } + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); - strcpy(bus->name, "miim-internal"); - miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]); - miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]); - bus->priv = &miim[INTERNAL]; + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; bus->read = mscc_miim_read; bus->write = mscc_miim_write; if (mdio_register(bus)) return NULL; - else - return bus; + + miim[miim_count].bus = bus; + return bus; } __weak void mscc_switch_reset(void) @@ -291,13 +378,87 @@ static void ocelot_port_init(struct ocelot_private *priv, int port) /* Make VLAN aware for CPU traffic */ writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | - MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0)); + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); /* Enable the port in the core */ - setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0), + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port), QSYS_SWITCH_PORT_MODE_PORT_ENA); } +static void serdes1g_write(void __iomem *base, u32 addr) +{ + u32 data; + + writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT | + HSIO_MCB_SERDES1G_CFG_ADDR(addr), + base + HSIO_MCB_SERDES1G_CFG); + + do { + data = readl(base + HSIO_MCB_SERDES1G_CFG); + } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT); +} + +static void serdes1g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) +{ + writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG); + + writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG); + writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0); + writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) | + HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) | + HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP | + HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM | + HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1), + base + HSIO_ANA_SERDES1G_IB_CFG); + writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) | + HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) | + HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) | + HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6), + base + HSIO_ANA_SERDES1G_DES_CFG); + writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) | + HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) | + HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) | + HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) | + HSIO_ANA_SERDES1G_OB_CFG_SLP(3), + base + HSIO_ANA_SERDES1G_OB_CFG); + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA | + HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) | + HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2, + base + HSIO_ANA_SERDES1G_PLL_CFG); + writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST, + base + HSIO_DIG_SERDES1G_MISC_CFG); + + serdes1g_write(base, addr); + + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE | + HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + serdes1g_write(base, addr); + + writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes1g_write(base, addr); +} + +static void serdes_setup(struct ocelot_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes1g_setup(priv->regs[HSIO], mask, + priv->ports[i].phy_mode); + } +} + static int ocelot_switch_init(struct ocelot_private *priv) { /* Reset switch & memories */ @@ -315,6 +476,7 @@ static int ocelot_switch_init(struct ocelot_private *priv) setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, SYS_SYSTEM_RST_CORE_ENA); + serdes_setup(priv); return 0; } @@ -331,7 +493,7 @@ static int ocelot_initialize(struct ocelot_private *priv) * Put fron ports in "port isolation modes" - i.e. they cant send * to other ports - via the PGID sorce masks. */ - for (i = 0; i <= MAX_PORT; i++) + for (i = 0; i < MAX_PORT; i++) writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i)); /* Flush queues */ @@ -341,7 +503,7 @@ static int ocelot_initialize(struct ocelot_private *priv) writel(SYS_FRM_AGING_ENA | (20000000 / 65), priv->regs[SYS] + SYS_FRM_AGING); - for (i = PORT0; i <= PORT3; i++) + for (i = 0; i < MAX_PORT; i++) ocelot_port_init(priv, i); ocelot_cpu_capture_setup(priv); @@ -433,43 +595,119 @@ static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp) return byte_cnt; } +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct ocelot_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + +static int external_bus(struct ocelot_private *priv, size_t port_index) +{ + return priv->ports[port_index].serdes_index != 0xff; +} + static int ocelot_probe(struct udevice *dev) { struct ocelot_private *priv = dev_get_priv(dev); - int ret, i; + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; + + if (!priv) + return -EINVAL; - struct { - enum ocelot_target id; - char *name; - } reg[] = { - { SYS, "sys" }, - { REW, "rew" }, - { QSYS, "qsys" }, - { ANA, "ana" }, - { QS, "qs" }, - { HSIO, "hsio" }, - { PORT0, "port0" }, - { PORT1, "port1" }, - { PORT2, "port2" }, - { PORT3, "port3" }, - }; - - for (i = 0; i < ARRAY_SIZE(reg); i++) { - priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name); - if (!priv->regs[reg[i].id]) { - pr_err - ("Error %d: can't get regs base addresses for %s\n", - ret, reg[i].name); + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { + debug + ("Error can't get regs base addresses for %s\n", + regs_names[i]); return -ENOMEM; } } - priv->bus[INTERNAL] = ocelot_mdiobus_init(dev); + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(struct mscc_miim_dev) * + OCELOT_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0, + &phandle); + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + ocelot_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff); + else + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + mscc_phy_reset(); - for (i = 0; i < 4; i++) { - phy_connect(priv->bus[INTERNAL], i, dev, - PHY_INTERFACE_MODE_NONE); + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy && external_bus(priv, i)) + board_phy_config(phy); } return 0; @@ -480,7 +718,7 @@ static int ocelot_remove(struct udevice *dev) struct ocelot_private *priv = dev_get_priv(dev); int i; - for (i = 0; i < NUM_PHY; i++) { + for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) { mdio_unregister(priv->bus[i]); mdio_free(priv->bus[i]); } diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c new file mode 100644 index 00000000000..2559f5d0cd1 --- /dev/null +++ b/drivers/net/mscc_eswitch/serval_switch.c @@ -0,0 +1,703 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Microsemi Corporation + */ + +#include <common.h> +#include <config.h> +#include <dm.h> +#include <dm/of_access.h> +#include <dm/of_addr.h> +#include <fdt_support.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <miiphy.h> +#include <net.h> +#include <wait_bit.h> + +#include "mscc_xfer.h" +#include "mscc_mac_table.h" + +#define GCB_MIIM_MII_STATUS 0x0 +#define GCB_MIIM_STAT_BUSY BIT(3) +#define GCB_MIIM_MII_CMD 0x8 +#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) +#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) +#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) +#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) +#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) +#define GCB_MIIM_MII_CMD_VLD BIT(31) +#define GCB_MIIM_DATA 0xC +#define GCB_MIIM_DATA_ERROR (0x2 << 16) + +#define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x)) +#define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) +#define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) +#define ANA_PORT_PORT_CFG(x) (0xc070 + 0x100 * (x)) +#define ANA_PORT_PORT_CFG_RECV_ENA BIT(6) +#define ANA_PGID(x) (0x9c00 + 4 * (x)) + +#define HSIO_ANA_SERDES1G_DES_CFG 0x3c +#define HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x) ((x) << 1) +#define HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x) ((x) << 5) +#define HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_IB_CFG 0x40 +#define HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x) ((x) << 6) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP BIT(9) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV BIT(11) +#define HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM BIT(13) +#define HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x) ((x) << 19) +#define HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x) ((x) << 24) +#define HSIO_ANA_SERDES1G_OB_CFG 0x44 +#define HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x) (x) +#define HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x) ((x) << 4) +#define HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x) ((x) << 10) +#define HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x) ((x) << 13) +#define HSIO_ANA_SERDES1G_OB_CFG_SLP(x) ((x) << 17) +#define HSIO_ANA_SERDES1G_SER_CFG 0x48 +#define HSIO_ANA_SERDES1G_COMMON_CFG 0x4c +#define HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE BIT(0) +#define HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE BIT(18) +#define HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST BIT(31) +#define HSIO_ANA_SERDES1G_PLL_CFG 0x50 +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA BIT(7) +#define HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x) ((x) << 8) +#define HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2 BIT(21) +#define HSIO_DIG_SERDES1G_DFT_CFG0 0x58 +#define HSIO_DIG_SERDES1G_MISC_CFG 0x6c +#define HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST BIT(0) +#define HSIO_MCB_SERDES1G_CFG 0x74 +#define HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT BIT(31) +#define HSIO_MCB_SERDES1G_CFG_ADDR(x) (x) + +#define SYS_FRM_AGING 0x584 +#define SYS_FRM_AGING_ENA BIT(20) +#define SYS_SYSTEM_RST_CFG 0x518 +#define SYS_SYSTEM_RST_MEM_INIT BIT(5) +#define SYS_SYSTEM_RST_MEM_ENA BIT(6) +#define SYS_SYSTEM_RST_CORE_ENA BIT(7) +#define SYS_PORT_MODE(x) (0x524 + 0x4 * (x)) +#define SYS_PORT_MODE_INCL_INJ_HDR(x) ((x) << 4) +#define SYS_PORT_MODE_INCL_XTR_HDR(x) ((x) << 2) +#define SYS_PAUSE_CFG(x) (0x65c + 0x4 * (x)) +#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0) + +#define QSYS_SWITCH_PORT_MODE(x) (0x15a34 + 0x4 * (x)) +#define QSYS_SWITCH_PORT_MODE_PORT_ENA BIT(13) +#define QSYS_EGR_NO_SHARING 0x15a9c +#define QSYS_QMAP 0x15adc + +/* Port registers */ +#define DEV_CLOCK_CFG 0x0 +#define DEV_CLOCK_CFG_LINK_SPEED_1000 1 +#define DEV_MAC_ENA_CFG 0x10 +#define DEV_MAC_ENA_CFG_RX_ENA BIT(4) +#define DEV_MAC_ENA_CFG_TX_ENA BIT(0) +#define DEV_MAC_IFG_CFG 0x24 +#define DEV_MAC_IFG_CFG_TX_IFG(x) ((x) << 8) +#define DEV_MAC_IFG_CFG_RX_IFG2(x) ((x) << 4) +#define DEV_MAC_IFG_CFG_RX_IFG1(x) (x) +#define PCS1G_CFG 0x3c +#define PCS1G_MODE_CFG_SGMII_MODE_ENA BIT(0) +#define PCS1G_MODE_CFG 0x40 +#define PCS1G_SD_CFG 0x44 +#define PCS1G_ANEG_CFG 0x48 +#define PCS1G_ANEG_CFG_ADV_ABILITY(x) ((x) << 16) + +#define QS_XTR_GRP_CFG(x) (4 * (x)) +#define QS_XTR_GRP_CFG_MODE(x) ((x) << 2) +#define QS_XTR_GRP_CFG_BYTE_SWAP BIT(0) +#define QS_INJ_GRP_CFG(x) (0x24 + (x) * 4) +#define QS_INJ_GRP_CFG_MODE(x) ((x) << 2) +#define QS_INJ_GRP_CFG_BYTE_SWAP BIT(0) + +#define IFH_INJ_BYPASS BIT(31) +#define IFH_TAG_TYPE_C 0 +#define MAC_VID 1 +#define CPU_PORT 11 +#define INTERNAL_PORT_MSK 0xFF +#define IFH_LEN 4 +#define ETH_ALEN 6 +#define PGID_BROADCAST 13 +#define PGID_UNICAST 14 + +static const char *const regs_names[] = { + "port0", "port1", "port2", "port3", "port4", "port5", "port6", + "port7", "port8", "port9", "port10", + "ana", "qs", "qsys", "rew", "sys", "hsio", +}; + +#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1 +#define MAX_PORT 11 + +enum serval_ctrl_regs { + ANA = MAX_PORT, + QS, + QSYS, + REW, + SYS, + HSIO, +}; + +#define SERVAL_MIIM_BUS_COUNT 2 + +struct serval_phy_port_t { + size_t phy_addr; + struct mii_dev *bus; + u8 serdes_index; + u8 phy_mode; +}; + +struct serval_private { + void __iomem *regs[REGS_NAMES_COUNT]; + struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT]; + struct serval_phy_port_t ports[MAX_PORT]; +}; + +struct mscc_miim_dev { + void __iomem *regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; +}; + +static const unsigned long serval_regs_qs[] = { + [MSCC_QS_XTR_RD] = 0x8, + [MSCC_QS_XTR_FLUSH] = 0x18, + [MSCC_QS_XTR_DATA_PRESENT] = 0x1c, + [MSCC_QS_INJ_WR] = 0x2c, + [MSCC_QS_INJ_CTRL] = 0x34, +}; + +static const unsigned long serval_regs_ana_table[] = { + [MSCC_ANA_TABLES_MACHDATA] = 0x9b34, + [MSCC_ANA_TABLES_MACLDATA] = 0x9b38, + [MSCC_ANA_TABLES_MACACCESS] = 0x9b3c, +}; + +static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT]; +static int miim_count = -1; + +static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) +{ + return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, + GCB_MIIM_STAT_BUSY, false, 250, false); +} + +static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + u32 val; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, + miim->regs + GCB_MIIM_MII_CMD); + + ret = mscc_miim_wait_ready(miim); + if (ret) + goto out; + + val = readl(miim->regs + GCB_MIIM_DATA); + if (val & GCB_MIIM_DATA_ERROR) { + ret = -EIO; + goto out; + } + + ret = val & 0xFFFF; + out: + return ret; +} + +static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; + int ret; + + ret = mscc_miim_wait_ready(miim); + if (ret < 0) + goto out; + + writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | + GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | + GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); + out: + return ret; +} + +static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, + unsigned long miim_size) +{ + struct mii_dev *bus; + + bus = mdio_alloc(); + if (!bus) + return NULL; + + ++miim_count; + sprintf(bus->name, "miim-bus%d", miim_count); + + miim[miim_count].regs = ioremap(miim_base, miim_size); + miim[miim_count].miim_base = miim_base; + miim[miim_count].miim_size = miim_size; + bus->priv = &miim[miim_count]; + bus->read = mscc_miim_read; + bus->write = mscc_miim_write; + + if (mdio_register(bus)) + return NULL; + + miim[miim_count].bus = bus; + return bus; +} + +static void serval_cpu_capture_setup(struct serval_private *priv) +{ + int i; + + /* map the 8 CPU extraction queues to CPU port 11 */ + writel(0, priv->regs[QSYS] + QSYS_QMAP); + + for (i = 0; i <= 1; i++) { + /* + * Do byte-swap and expect status after last data word + * Extraction: Mode: manual extraction) | Byte_swap + */ + writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP, + priv->regs[QS] + QS_XTR_GRP_CFG(i)); + /* + * Injection: Mode: manual extraction | Byte_swap + */ + writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP, + priv->regs[QS] + QS_INJ_GRP_CFG(i)); + } + + for (i = 0; i <= 1; i++) + /* Enable IFH insertion/parsing on CPU ports */ + writel(SYS_PORT_MODE_INCL_INJ_HDR(1) | + SYS_PORT_MODE_INCL_XTR_HDR(1), + priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i)); + /* + * Setup the CPU port as VLAN aware to support switching frames + * based on tags + */ + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT)); + + /* Disable learning (only RECV_ENA must be set) */ + writel(ANA_PORT_PORT_CFG_RECV_ENA, + priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT)); + + /* Enable switching to/from cpu port */ + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT), + QSYS_SWITCH_PORT_MODE_PORT_ENA); + + /* No pause on CPU port - not needed (off by default) */ + clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT), + SYS_PAUSE_CFG_PAUSE_ENA); + + setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT)); +} + +static void serval_port_init(struct serval_private *priv, int port) +{ + void __iomem *regs = priv->regs[port]; + + /* Enable PCS */ + writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG); + + /* Disable Signal Detect */ + writel(0, regs + PCS1G_SD_CFG); + + /* Enable MAC RX and TX */ + writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, + regs + DEV_MAC_ENA_CFG); + + /* Clear sgmii_mode_ena */ + writel(0, regs + PCS1G_MODE_CFG); + + /* + * Clear sw_resolve_ena(bit 0) and set adv_ability to + * something meaningful just in case + */ + writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG); + + /* Set MAC IFG Gaps */ + writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) | + DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG); + + /* Set link speed and release all resets */ + writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG); + + /* Make VLAN aware for CPU traffic */ + writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) | + MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port)); + + /* Enable the port in the core */ + setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port), + QSYS_SWITCH_PORT_MODE_PORT_ENA); +} + +static void serdes_write(void __iomem *base, u32 addr) +{ + u32 data; + + writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT | + HSIO_MCB_SERDES1G_CFG_ADDR(addr), + base + HSIO_MCB_SERDES1G_CFG); + + do { + data = readl(base + HSIO_MCB_SERDES1G_CFG); + } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT); + + mdelay(100); +} + +static void serdes1g_setup(void __iomem *base, uint32_t addr, + phy_interface_t interface) +{ + writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG); + writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0); + writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) | + HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) | + HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP | + HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM | + HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1), + base + HSIO_ANA_SERDES1G_IB_CFG); + writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) | + HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) | + HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) | + HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6), + base + HSIO_ANA_SERDES1G_DES_CFG); + writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) | + HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) | + HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) | + HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) | + HSIO_ANA_SERDES1G_OB_CFG_SLP(3), + base + HSIO_ANA_SERDES1G_OB_CFG); + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA | + HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) | + HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2, + base + HSIO_ANA_SERDES1G_PLL_CFG); + writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST, + base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes_write(base, addr); + + writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE | + HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE | + HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST, + base + HSIO_ANA_SERDES1G_COMMON_CFG); + serdes_write(base, addr); + + writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG); + serdes_write(base, addr); +} + +static void serdes_setup(struct serval_private *priv) +{ + size_t mask; + int i = 0; + + for (i = 0; i < MAX_PORT; ++i) { + if (!priv->ports[i].bus) + continue; + + mask = BIT(priv->ports[i].serdes_index); + serdes1g_setup(priv->regs[HSIO], mask, + priv->ports[i].phy_mode); + } +} + +static int serval_switch_init(struct serval_private *priv) +{ + /* Reset switch & memories */ + writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT, + priv->regs[SYS] + SYS_SYSTEM_RST_CFG); + + if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, + SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) { + pr_err("Timeout in memory reset\n"); + return -EIO; + } + + /* Enable switch core */ + setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG, + SYS_SYSTEM_RST_CORE_ENA); + + serdes_setup(priv); + + return 0; +} + +static int serval_initialize(struct serval_private *priv) +{ + int ret, i; + + /* Initialize switch memories, enable core */ + ret = serval_switch_init(priv); + if (ret) + return ret; + + /* Flush queues */ + mscc_flush(priv->regs[QS], serval_regs_qs); + + /* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */ + writel(SYS_FRM_AGING_ENA | (20000000 / 65), + priv->regs[SYS] + SYS_FRM_AGING); + + for (i = 0; i < MAX_PORT; i++) + serval_port_init(priv, i); + + serval_cpu_capture_setup(priv); + + debug("Ports enabled\n"); + + return 0; +} + +static int serval_write_hwaddr(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, + pdata->enetaddr, PGID_UNICAST); + + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); + + return 0; +} + +static int serval_start(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff }; + int ret; + + ret = serval_initialize(priv); + if (ret) + return ret; + + /* Set MAC address tables entries for CPU redirection */ + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac, + PGID_BROADCAST); + + writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK, + priv->regs[ANA] + ANA_PGID(PGID_BROADCAST)); + + /* It should be setup latter in serval_write_hwaddr */ + mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, + pdata->enetaddr, PGID_UNICAST); + + writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST)); + return 0; +} + +static void serval_stop(struct udevice *dev) +{ + writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET); + writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST); +} + +static int serval_send(struct udevice *dev, void *packet, int length) +{ + struct serval_private *priv = dev_get_priv(dev); + u32 ifh[IFH_LEN]; + u32 *buf = packet; + + /* + * Generate the IFH for frame injection + * + * The IFH is a 128bit-value + * bit 127: bypass the analyzer processing + * bit 57-67: destination mask + * bit 28-29: pop_cnt: 3 disables all rewriting of the frame + * bit 20-27: cpu extraction queue mask + * bit 16: tag type 0: C-tag, 1: S-tag + * bit 0-11: VID + */ + ifh[0] = IFH_INJ_BYPASS; + ifh[1] = (0x07); + ifh[2] = (0x7f) << 25; + ifh[3] = (IFH_TAG_TYPE_C << 16); + + return mscc_send(priv->regs[QS], serval_regs_qs, + ifh, IFH_LEN, buf, length); +} + +static int serval_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct serval_private *priv = dev_get_priv(dev); + u32 *rxbuf = (u32 *)net_rx_packets[0]; + int byte_cnt = 0; + + byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN, + false); + + *packetp = net_rx_packets[0]; + + return byte_cnt; +} + +static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size) +{ + int i = 0; + + for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i) + if (miim[i].miim_base == base && miim[i].miim_size == size) + return miim[i].bus; + + return NULL; +} + +static void add_port_entry(struct serval_private *priv, size_t index, + size_t phy_addr, struct mii_dev *bus, + u8 serdes_index, u8 phy_mode) +{ + priv->ports[index].phy_addr = phy_addr; + priv->ports[index].bus = bus; + priv->ports[index].serdes_index = serdes_index; + priv->ports[index].phy_mode = phy_mode; +} + +static int serval_probe(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + int i, ret; + struct resource res; + fdt32_t faddr; + phys_addr_t addr_base; + unsigned long addr_size; + ofnode eth_node, node, mdio_node; + size_t phy_addr; + struct mii_dev *bus; + struct ofnode_phandle_args phandle; + struct phy_device *phy; + + if (!priv) + return -EINVAL; + + /* Get registers and map them to the private structure */ + for (i = 0; i < ARRAY_SIZE(regs_names); i++) { + priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]); + if (!priv->regs[i]) { + debug + ("Error can't get regs base addresses for %s\n", + regs_names[i]); + return -ENOMEM; + } + } + + /* Initialize miim buses */ + memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT); + + /* iterate all the ports and find out on which bus they are */ + i = 0; + eth_node = dev_read_first_subnode(dev); + for (node = ofnode_first_subnode(eth_node); + ofnode_valid(node); + node = ofnode_next_subnode(node)) { + if (ofnode_read_resource(node, 0, &res)) + return -ENOMEM; + i = res.start; + + ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL, + 0, 0, &phandle); + if (ret) + continue; + + /* Get phy address on mdio bus */ + if (ofnode_read_resource(phandle.node, 0, &res)) + return -ENOMEM; + phy_addr = res.start; + + /* Get mdio node */ + mdio_node = ofnode_get_parent(phandle.node); + + if (ofnode_read_resource(mdio_node, 0, &res)) + return -ENOMEM; + faddr = cpu_to_fdt32(res.start); + + addr_base = ofnode_translate_address(mdio_node, &faddr); + addr_size = res.end - res.start; + + /* If the bus is new then create a new bus */ + if (!get_mdiobus(addr_base, addr_size)) + priv->bus[miim_count] = + serval_mdiobus_init(addr_base, addr_size); + + /* Connect mdio bus with the port */ + bus = get_mdiobus(addr_base, addr_size); + + /* Get serdes info */ + ret = ofnode_parse_phandle_with_args(node, "phys", NULL, + 3, 0, &phandle); + if (ret) + return -ENOMEM; + + add_port_entry(priv, i, phy_addr, bus, phandle.args[1], + phandle.args[2]); + } + + for (i = 0; i < MAX_PORT; i++) { + if (!priv->ports[i].bus) + continue; + + phy = phy_connect(priv->ports[i].bus, + priv->ports[i].phy_addr, dev, + PHY_INTERFACE_MODE_NONE); + if (phy) + board_phy_config(phy); + } + + return 0; +} + +static int serval_remove(struct udevice *dev) +{ + struct serval_private *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) { + mdio_unregister(priv->bus[i]); + mdio_free(priv->bus[i]); + } + + return 0; +} + +static const struct eth_ops serval_ops = { + .start = serval_start, + .stop = serval_stop, + .send = serval_send, + .recv = serval_recv, + .write_hwaddr = serval_write_hwaddr, +}; + +static const struct udevice_id mscc_serval_ids[] = { + {.compatible = "mscc,vsc7418-switch"}, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(serval) = { + .name = "serval-switch", + .id = UCLASS_ETH, + .of_match = mscc_serval_ids, + .probe = serval_probe, + .remove = serval_remove, + .ops = &serval_ops, + .priv_auto_alloc_size = sizeof(struct serval_private), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index cc09404830a..0ef814c78b9 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -1130,13 +1130,14 @@ static int mtk_eth_ofdata_to_platdata(struct udevice *dev) &priv->rst_gpio, GPIOD_IS_OUT); } } else { - subnode = ofnode_find_subnode(dev_ofnode(dev), "phy-handle"); - if (!ofnode_valid(subnode)) { + ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, + 0, &args); + if (ret) { printf("error: phy-handle is not specified\n"); return ret; } - priv->phy_addr = ofnode_read_s32_default(subnode, "reg", -1); + priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1); if (priv->phy_addr < 0) { printf("error: phy address is not specified\n"); return ret; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3dc0822d9c2..2a3da068c90 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -119,21 +119,19 @@ config PHY_MICREL bool "Micrel Ethernet PHYs support" help Enable support for the GbE PHYs manufactured by Micrel (now - a part of Microchip). This includes drivers for the KSZ804, - KSZ8031, KSZ8051, KSZ8081, KSZ8895, KSZ886x, KSZ8721 - either/or KSZ9021 (see the "Micrel KSZ9021 family support" - config option for details), and KSZ9031 (if configured). + a part of Microchip). This includes drivers for the KSZ804, KSZ8031, + KSZ8051, KSZ8081, KSZ8895, KSZ886x and KSZ8721 (if "Micrel KSZ8xxx + family support" is selected) and the KSZ9021 and KSZ9031 (if "Micrel + KSZ90x1 family support" is selected). if PHY_MICREL config PHY_MICREL_KSZ9021 bool - select PHY_GIGE select PHY_MICREL_KSZ90X1 config PHY_MICREL_KSZ9031 bool - select PHY_GIGE select PHY_MICREL_KSZ90X1 config PHY_MICREL_KSZ90X1 @@ -146,20 +144,13 @@ config PHY_MICREL_KSZ90X1 delays configured in the device tree will be applied to the PHY during initialization. - This should not be enabled at the same time with PHY_MICREL_KSZ8XXX - as the KSZ9021 and KS8721 share the same ID. - config PHY_MICREL_KSZ8XXX bool "Micrel KSZ8xxx family support" - default y if !PHY_MICREL_KSZ90X1 help - Enable support for the 8000 series GbE PHYs manufactured by Micrel + Enable support for the 8000 series 10/100 PHYs manufactured by Micrel (now a part of Microchip). This includes drivers for the KSZ804, KSZ8031, KSZ8051, KSZ8081, KSZ8895, KSZ886x, and KSZ8721. - This should not be enabled at the same time with PHY_MICREL_KSZ90X1 - as the KSZ9021 and KS8721 share the same ID. - endif # PHY_MICREL config PHY_MSCC @@ -202,6 +193,26 @@ config RTL8211X_PHY_FORCE_MASTER If unsure, say N. +config RTL8211F_PHY_FORCE_EEE_RXC_ON + bool "Ethernet PHY RTL8211F: do not stop receiving the xMII clock during LPI" + depends on PHY_REALTEK + default n + help + The IEEE 802.3az-2010 (EEE) standard provides a protocol to coordinate + transitions to/from a lower power consumption level (Low Power Idle + mode) based on link utilization. When no packets are being + transmitted, the system goes to Low Power Idle mode to save power. + + Under particular circumstances this setting can cause issues where + the PHY is unable to transmit or receive any packet when in LPI mode. + The problem is caused when the PHY is configured to stop receiving + the xMII clock while it is signaling LPI. For some PHYs the bit + configuring this behavior is set by the Linux kernel, causing the + issue in U-Boot on reboot if the PHY retains the register value. + + Default n, which means that the PHY state is not changed. To work + around the issues, change this setting to y. + config PHY_SMSC bool "Microchip(SMSC) Ethernet PHYs support" diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 12df09877de..5c3298d612c 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -303,9 +303,14 @@ int aquantia_config(struct phy_device *phydev) AQUANTIA_SYSTEM_INTERFACE_SR); /* If SI is USXGMII then start USXGMII autoneg */ if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) { + reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, + AQUANTIA_VENDOR_PROVISIONING_REG); + + reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA; + phy_write(phydev, MDIO_MMD_PHYXS, AQUANTIA_VENDOR_PROVISIONING_REG, - AQUANTIA_USX_AUTONEG_CONTROL_ENA); + reg_val1); printf("%s: system interface USXGMII\n", phydev->dev->name); } else { diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c index 3411150ab9d..daa57ce33c1 100644 --- a/drivers/net/phy/micrel_ksz8xxx.c +++ b/drivers/net/phy/micrel_ksz8xxx.c @@ -147,11 +147,13 @@ static struct phy_driver ksz8895_driver = { .shutdown = &genphy_shutdown, }; -/* Micrel used the exact same part number for the KSZ9021. */ +/* Micrel used the exact same model number for the KSZ9021, + * so the revision number is used to distinguish them. + */ static struct phy_driver KS8721_driver = { .name = "Micrel KS8721BL", - .uid = 0x221610, - .mask = 0xfffff0, + .uid = 0x221618, + .mask = 0xfffffc, .features = PHY_BASIC_FEATURES, .config = &genphy_config, .startup = &genphy_startup, diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index 63e7b0242b9..f18e40a2fea 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -33,10 +33,14 @@ #define CTRL1000_CONFIG_MASTER (1 << 11) #define CTRL1000_MANUAL_CONFIG (1 << 12) +#define KSZ9021_PS_TO_REG 120 + /* KSZ9031 PHY Registers */ #define MII_KSZ9031_MMD_ACCES_CTRL 0x0d #define MII_KSZ9031_MMD_REG_DATA 0x0e +#define KSZ9031_PS_TO_REG 60 + static int ksz90xx_startup(struct phy_device *phydev) { unsigned phy_ctl; @@ -102,20 +106,28 @@ static const struct ksz90x1_reg_field ksz9031_clk_grp[] = { }; static int ksz90x1_of_config_group(struct phy_device *phydev, - struct ksz90x1_ofcfg *ofcfg) + struct ksz90x1_ofcfg *ofcfg, + int ps_to_regval) { struct udevice *dev = phydev->dev; struct phy_driver *drv = phydev->drv; - const int ps_to_regval = 60; int val[4]; int i, changed = 0, offset, max; u16 regval = 0; + ofnode node; if (!drv || !drv->writeext) return -EOPNOTSUPP; + /* Look for a PHY node under the Ethernet node */ + node = dev_read_subnode(dev, "ethernet-phy"); + if (!ofnode_valid(node)) { + /* No node found, look in the Ethernet node */ + node = dev_ofnode(dev); + } + for (i = 0; i < ofcfg->grpsz; i++) { - val[i] = dev_read_u32_default(dev, ofcfg->grp[i].name, ~0); + val[i] = ofnode_read_u32_default(node, ofcfg->grp[i].name, ~0); offset = ofcfg->grp[i].off; if (val[i] == -1) { /* Default register value for KSZ9021 */ @@ -148,7 +160,8 @@ static int ksz9021_of_config(struct phy_device *phydev) int i, ret = 0; for (i = 0; i < ARRAY_SIZE(ofcfg); i++) { - ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); + ret = ksz90x1_of_config_group(phydev, &ofcfg[i], + KSZ9021_PS_TO_REG); if (ret) return ret; } @@ -167,7 +180,8 @@ static int ksz9031_of_config(struct phy_device *phydev) int i, ret = 0; for (i = 0; i < ARRAY_SIZE(ofcfg); i++) { - ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); + ret = ksz90x1_of_config_group(phydev, &ofcfg[i], + KSZ9031_PS_TO_REG); if (ret) return ret; } @@ -271,7 +285,7 @@ static int ksz9021_config(struct phy_device *phydev) static struct phy_driver ksz9021_driver = { .name = "Micrel ksz9021", .uid = 0x221610, - .mask = 0xfffff0, + .mask = 0xfffffe, .features = PHY_GBIT_FEATURES, .config = &ksz9021_config, .startup = &ksz90xx_startup, diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 4e8d2943eee..c1c1af9abdb 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -462,6 +462,18 @@ static LIST_HEAD(phy_drivers); int phy_init(void) { +#ifdef CONFIG_NEEDS_MANUAL_RELOC + /* + * The pointers inside phy_drivers also needs to be updated incase of + * manual reloc, without which these points to some invalid + * pre reloc address and leads to invalid accesses, hangs. + */ + struct list_head *head = &phy_drivers; + + head->next = (void *)head->next + gd->reloc_off; + head->prev = (void *)head->prev + gd->reloc_off; +#endif + #ifdef CONFIG_B53_SWITCH phy_b53_init(); #endif @@ -549,6 +561,10 @@ int phy_register(struct phy_driver *drv) drv->readext += gd->reloc_off; if (drv->writeext) drv->writeext += gd->reloc_off; + if (drv->read_mmd) + drv->read_mmd += gd->reloc_off; + if (drv->write_mmd) + drv->write_mmd += gd->reloc_off; #endif return 0; } @@ -655,7 +671,10 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, dev->drv = get_phy_driver(dev, interface); - phy_probe(dev); + if (phy_probe(dev)) { + printf("%s, PHY probe failed\n", __func__); + return NULL; + } if (addr >= 0 && addr < PHY_MAX_ADDR) bus->phymap[addr] = dev; diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index dd45e11b3ad..8f1d7596325 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -12,6 +12,7 @@ #define PHY_RTL8211x_FORCE_MASTER BIT(1) #define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2) +#define PHY_RTL8211F_FORCE_EEE_RXC_ON BIT(3) #define PHY_AUTONEGOTIATE_TIMEOUT 5000 @@ -102,6 +103,15 @@ static int rtl8211e_probe(struct phy_device *phydev) return 0; } +static int rtl8211f_probe(struct phy_device *phydev) +{ +#ifdef CONFIG_RTL8211F_PHY_FORCE_EEE_RXC_ON + phydev->flags |= PHY_RTL8211F_FORCE_EEE_RXC_ON; +#endif + + return 0; +} + /* RealTek RTL8211x */ static int rtl8211x_config(struct phy_device *phydev) { @@ -151,6 +161,14 @@ static int rtl8211f_config(struct phy_device *phydev) { u16 reg; + if (phydev->flags & PHY_RTL8211F_FORCE_EEE_RXC_ON) { + unsigned int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); + reg &= ~MDIO_PCS_CTRL1_CLKSTOP_EN; + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, reg); + } + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); phy_write(phydev, MDIO_DEVAD_NONE, @@ -360,6 +378,7 @@ static struct phy_driver RTL8211F_driver = { .uid = 0x1cc916, .mask = 0xffffff, .features = PHY_GBIT_FEATURES, + .probe = &rtl8211f_probe, .config = &rtl8211f_config, .startup = &rtl8211f_startup, .shutdown = &genphy_shutdown, diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 6db6edd0d0c..25f1332ca98 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -73,16 +73,6 @@ #define MII_DP83867_CFG2_SPEEDOPT_INTLOW 0x2000 #define MII_DP83867_CFG2_MASK 0x003F -#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */ -#define MII_MMD_DATA 0x0e /* MMD Access Data Register */ - -/* MMD Access Control register fields */ -#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/ -#define MII_MMD_CTRL_ADDR 0x0000 /* Address */ -#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */ -#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */ -#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */ - /* User setting - can be taken from DTS */ #define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS #define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS @@ -116,88 +106,20 @@ struct dp83867_private { int clk_output_sel; }; -/** - * phy_read_mmd_indirect - reads data from the MMD registers - * @phydev: The PHY device bus - * @prtad: MMD Address - * @devad: MMD DEVAD - * @addr: PHY address on the MII bus - * - * Description: it reads data from the MMD registers (clause 22 to access to - * clause 45) of the specified phy address. - * To read these registers we have: - * 1) Write reg 13 // DEVAD - * 2) Write reg 14 // MMD Address - * 3) Write reg 13 // MMD Data Command for MMD DEVAD - * 3) Read reg 14 // Read MMD data - */ -int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, - int devad, int addr) -{ - int value = -1; - - /* Write the desired MMD Devad */ - phy_write(phydev, addr, MII_MMD_CTRL, devad); - - /* Write the desired MMD register address */ - phy_write(phydev, addr, MII_MMD_DATA, prtad); - - /* Select the Function : DATA with no post increment */ - phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); - - /* Read the content of the MMD's selected register */ - value = phy_read(phydev, addr, MII_MMD_DATA); - return value; -} - -/** - * phy_write_mmd_indirect - writes data to the MMD registers - * @phydev: The PHY device - * @prtad: MMD Address - * @devad: MMD DEVAD - * @addr: PHY address on the MII bus - * @data: data to write in the MMD register - * - * Description: Write data from the MMD registers of the specified - * phy address. - * To write these registers we have: - * 1) Write reg 13 // DEVAD - * 2) Write reg 14 // MMD Address - * 3) Write reg 13 // MMD Data Command for MMD DEVAD - * 3) Write reg 14 // Write MMD data - */ -void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, - int devad, int addr, u32 data) -{ - /* Write the desired MMD Devad */ - phy_write(phydev, addr, MII_MMD_CTRL, devad); - - /* Write the desired MMD register address */ - phy_write(phydev, addr, MII_MMD_DATA, prtad); - - /* Select the Function : DATA with no post increment */ - phy_write(phydev, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); - - /* Write the data into MMD's selected register */ - phy_write(phydev, addr, MII_MMD_DATA, data); -} - static int dp83867_config_port_mirroring(struct phy_device *phydev) { struct dp83867_private *dp83867 = (struct dp83867_private *)phydev->priv; u16 val; - val = phy_read_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, - phydev->addr); + val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4); if (dp83867->port_mirroring == DP83867_PORT_MIRRORING_EN) val |= DP83867_CFG4_PORT_MIRROR_EN; else val &= ~DP83867_CFG4_PORT_MIRROR_EN; - phy_write_mmd_indirect(phydev, DP83867_CFG4, DP83867_DEVADDR, - phydev->addr, val); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val); return 0; } @@ -216,6 +138,10 @@ static int dp83867_of_init(struct phy_device *phydev) /* Optional configuration */ + node = phy_get_ofnode(phydev); + if (!ofnode_valid(node)) + return -EINVAL; + /* * Keep the default value if ti,clk-output-sel is not set * or to high @@ -225,10 +151,6 @@ static int dp83867_of_init(struct phy_device *phydev) ofnode_read_u32_default(node, "ti,clk-output-sel", DP83867_CLK_O_SEL_REF_CLK); - node = phy_get_ofnode(phydev); - if (!ofnode_valid(node)) - return -EINVAL; - if (ofnode_read_bool(node, "ti,max-output-impedance")) dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; else if (ofnode_read_bool(node, "ti,min-output-impedance")) @@ -257,13 +179,13 @@ static int dp83867_of_init(struct phy_device *phydev) /* Clock output selection if muxing property is set */ if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) { - val = phy_read_mmd_indirect(phydev, DP83867_IO_MUX_CFG, - DP83867_DEVADDR, phydev->addr); + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG); val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK; val |= (dp83867->clk_output_sel << DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT); - phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG, - DP83867_DEVADDR, phydev->addr, val); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG, val); } return 0; @@ -308,11 +230,11 @@ static int dp83867_config(struct phy_device *phydev) /* Mode 1 or 2 workaround */ if (dp83867->rxctrl_strap_quirk) { - val = phy_read_mmd_indirect(phydev, DP83867_CFG4, - DP83867_DEVADDR, phydev->addr); + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_CFG4); val &= ~BIT(7); - phy_write_mmd_indirect(phydev, DP83867_CFG4, - DP83867_DEVADDR, phydev->addr, val); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_CFG4, val); } if (phy_interface_is_rgmii(phydev)) { @@ -332,8 +254,8 @@ static int dp83867_config(struct phy_device *phydev) * register's bit 11 (marked as RESERVED). */ - bs = phy_read_mmd_indirect(phydev, DP83867_STRAP_STS1, - DP83867_DEVADDR, phydev->addr); + bs = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_STRAP_STS1); val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); if (bs & DP83867_STRAP_STS1_RESERVED) { val &= ~DP83867_PHYCR_RESERVED_MASK; @@ -354,8 +276,8 @@ static int dp83867_config(struct phy_device *phydev) MII_DP83867_CFG2_SPEEDOPT_INTLOW); phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_CFG2, cfg2); - phy_write_mmd_indirect(phydev, DP83867_RGMIICTL, - DP83867_DEVADDR, phydev->addr, 0x0); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIICTL, 0x0); phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, DP83867_PHYCTRL_SGMIIEN | @@ -367,8 +289,8 @@ static int dp83867_config(struct phy_device *phydev) } if (phy_interface_is_rgmii(phydev)) { - val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL, - DP83867_DEVADDR, phydev->addr); + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIICTL); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) val |= (DP83867_RGMII_TX_CLK_DELAY_EN | @@ -380,26 +302,24 @@ static int dp83867_config(struct phy_device *phydev) if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) val |= DP83867_RGMII_RX_CLK_DELAY_EN; - phy_write_mmd_indirect(phydev, DP83867_RGMIICTL, - DP83867_DEVADDR, phydev->addr, val); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIICTL, val); delay = (dp83867->rx_id_delay | (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); - phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL, - DP83867_DEVADDR, phydev->addr, delay); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIIDCTL, delay); if (dp83867->io_impedance >= 0) { - val = phy_read_mmd_indirect(phydev, - DP83867_IO_MUX_CFG, - DP83867_DEVADDR, - phydev->addr); + val = phy_read_mmd(phydev, + DP83867_DEVADDR, + DP83867_IO_MUX_CFG); val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; val |= dp83867->io_impedance & DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; - phy_write_mmd_indirect(phydev, DP83867_IO_MUX_CFG, - DP83867_DEVADDR, phydev->addr, - val); + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG, val); } } diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 749562db960..11abe5e0c9e 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -46,6 +46,8 @@ #define CSR_OPS 0x0000000F #define CSR_OPS_CONFIG BIT(1) +#define APSR_TDM BIT(14) + #define TCCR_TSRQ0 BIT(0) #define RFLR_RFL_MIN 0x05EE @@ -389,9 +391,14 @@ static int ravb_dmac_init(struct udevice *dev) /* FIFO size set */ writel(0x00222210, eth->iobase + RAVB_REG_TGC); - /* Delay CLK: 2ns */ - if (pdata->max_speed == 1000) - writel(BIT(14), eth->iobase + RAVB_REG_APSR); + /* Delay CLK: 2ns (not applicable on R-Car E3/D3) */ + if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77990) || + (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995)) + return 0; + + if ((pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || + (pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID)) + writel(APSR_TDM, eth->iobase + RAVB_REG_APSR); return 0; } diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index a78f3d233f1..521e5909a25 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -257,6 +257,7 @@ static struct { {"RTL-8168/8111g", 0x4c, 0xff7e1880,}, {"RTL-8101e", 0x34, 0xff7e1880,}, {"RTL-8100e", 0x32, 0xff7e1880,}, + {"RTL-8168h/8111h", 0x54, 0xff7e1880,}, }; enum _DescStatusBit { @@ -301,7 +302,7 @@ static unsigned char rxdata[RX_BUF_LEN]; */ #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning cache-line size is larger than descriptor size #endif #endif @@ -941,6 +942,23 @@ static void rtl_halt(struct eth_device *dev) } #endif +#ifdef CONFIG_DM_ETH +static int rtl8169_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + unsigned int i; + + RTL_W8(Cfg9346, Cfg9346_Unlock); + + for (i = 0; i < MAC_ADDR_LEN; i++) + RTL_W8(MAC0 + i, plat->enetaddr[i]); + + RTL_W8(Cfg9346, Cfg9346_Lock); + + return 0; +} +#endif + /************************************************************************** INIT - Look for an adapter, this routine's visible to the outside ***************************************************************************/ @@ -1195,6 +1213,7 @@ static const struct eth_ops rtl8169_eth_ops = { .send = rtl8169_eth_send, .recv = rtl8169_eth_recv, .stop = rtl8169_eth_stop, + .write_hwaddr = rtl8169_write_hwaddr, }; static const struct udevice_id rtl8169_eth_ids[] = { diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 4646f2ba4ec..da79b766a62 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -34,7 +34,8 @@ # error "Please define CONFIG_SH_ETHER_PHY_ADDR" #endif -#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && !defined(CONFIG_SYS_DCACHE_OFF) +#if defined(CONFIG_SH_ETHER_CACHE_WRITEBACK) && \ + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) #define flush_cache_wback(addr, len) \ flush_dcache_range((u32)addr, \ (u32)(addr + ALIGN(len, CONFIG_SH_ETHER_ALIGNE_SIZE))) @@ -425,7 +426,7 @@ static int sh_eth_phy_regs_config(struct sh_eth_dev *eth) sh_eth_write(port_info, GECMR_100B, GECMR); #elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) sh_eth_write(port_info, 1, RTRATE); -#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_RCAR_GEN2) +#elif defined(CONFIG_RCAR_GEN2) val = ECMR_RTM; #endif } else if (phy->speed == 10) { @@ -806,9 +807,11 @@ static int sh_ether_probe(struct udevice *udev) priv->iobase = pdata->iobase; +#if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(udev, 0, &priv->clk); if (ret < 0) return ret; +#endif ret = dev_read_phandle_with_args(udev, "phy-handle", NULL, 0, 0, &phandle_args); if (!ret) { @@ -843,9 +846,11 @@ static int sh_ether_probe(struct udevice *udev) eth->port_info[eth->port].iobase = (void __iomem *)(BASE_IO_ADDR + 0x800 * eth->port); +#if CONFIG_IS_ENABLED(CLK) ret = clk_enable(&priv->clk); if (ret) goto err_mdio_register; +#endif ret = sh_eth_phy_config(udev); if (ret) { @@ -856,7 +861,9 @@ static int sh_ether_probe(struct udevice *udev) return 0; err_phy_config: +#if CONFIG_IS_ENABLED(CLK) clk_disable(&priv->clk); +#endif err_mdio_register: mdio_free(mdiodev); return ret; @@ -868,7 +875,9 @@ static int sh_ether_remove(struct udevice *udev) struct sh_eth_dev *eth = &priv->shdev; struct sh_eth_info *port_info = ð->port_info[eth->port]; +#if CONFIG_IS_ENABLED(CLK) clk_disable(&priv->clk); +#endif free(port_info->phydev); mdio_unregister(priv->bus); mdio_free(priv->bus); @@ -917,6 +926,7 @@ int sh_ether_ofdata_to_platdata(struct udevice *dev) } static const struct udevice_id sh_ether_ids[] = { + { .compatible = "renesas,ether-r7s72100" }, { .compatible = "renesas,ether-r8a7790" }, { .compatible = "renesas,ether-r8a7791" }, { .compatible = "renesas,ether-r8a7793" }, diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index cd8190062a6..e1bbd4913f8 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -228,6 +228,60 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [RMII_MII] = 0x0790, }; +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, + [PIR] = 0x0520, + [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, +}; + static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { [ECMR] = 0x0100, [RFLR] = 0x0108, @@ -295,9 +349,6 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #define SH_ETH_TYPE_ETHER #define BASE_IO_ADDR 0xfef00000 #endif -#elif defined(CONFIG_CPU_SH7724) -#define SH_ETH_TYPE_ETHER -#define BASE_IO_ADDR 0xA4600000 #elif defined(CONFIG_R8A7740) #define SH_ETH_TYPE_GETHER #define BASE_IO_ADDR 0xE9A00000 @@ -606,6 +657,8 @@ static inline unsigned long sh_eth_reg_addr(struct sh_eth_info *port, 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 diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 98bd7a58232..c0a440886e2 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -138,7 +138,9 @@ struct emac_eth_dev { struct phy_device *phydev; struct mii_dev *bus; struct clk tx_clk; + struct clk ephy_clk; struct reset_ctl tx_rst; + struct reset_ctl ephy_rst; #ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio; #endif @@ -653,7 +655,6 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev) static int sun8i_emac_board_setup(struct emac_eth_dev *priv) { - struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; int ret; ret = clk_enable(&priv->tx_clk); @@ -670,16 +671,20 @@ static int sun8i_emac_board_setup(struct emac_eth_dev *priv) } } - if (priv->variant == H3_EMAC) { - /* Only H3/H5 have clock controls for internal EPHY */ - if (priv->use_internal_phy) { - /* Set clock gating for ephy */ - setbits_le32(&ccm->bus_gate4, - BIT(AHB_GATE_OFFSET_EPHY)); - - /* Deassert EPHY */ - setbits_le32(&ccm->ahb_reset2_cfg, - BIT(AHB_RESET_OFFSET_EPHY)); + /* Only H3/H5 have clock controls for internal EPHY */ + if (clk_valid(&priv->ephy_clk)) { + ret = clk_enable(&priv->ephy_clk); + if (ret) { + dev_err(dev, "failed to enable EPHY TX clock\n"); + return ret; + } + } + + if (reset_valid(&priv->ephy_rst)) { + ret = reset_deassert(&priv->ephy_rst); + if (ret) { + dev_err(dev, "failed to deassert EPHY TX clock\n"); + return ret; } } @@ -839,6 +844,44 @@ static const struct eth_ops sun8i_emac_eth_ops = { .stop = sun8i_emac_eth_stop, }; +static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv) +{ + int node, ret; + + /* look for mdio-mux node for internal PHY node */ + node = fdt_path_offset(gd->fdt_blob, + "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1"); + if (node < 0) { + debug("failed to get mdio-mux with internal PHY\n"); + return node; + } + + ret = fdt_node_check_compatible(gd->fdt_blob, node, + "allwinner,sun8i-h3-mdio-internal"); + if (ret < 0) { + debug("failed to find mdio-internal node\n"); + return ret; + } + + ret = clk_get_by_index_nodev(offset_to_ofnode(node), 0, + &priv->ephy_clk); + if (ret) { + dev_err(dev, "failed to get EPHY TX clock\n"); + return ret; + } + + ret = reset_get_by_index_nodev(offset_to_ofnode(node), 0, + &priv->ephy_rst); + if (ret) { + dev_err(dev, "failed to get EPHY TX reset\n"); + return ret; + } + + priv->use_internal_phy = true; + + return 0; +} + static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) { struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev); @@ -920,12 +963,9 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) } if (priv->variant == H3_EMAC) { - int parent = fdt_parent_offset(gd->fdt_blob, offset); - - if (parent >= 0 && - !fdt_node_check_compatible(gd->fdt_blob, parent, - "allwinner,sun8i-h3-mdio-internal")) - priv->use_internal_phy = true; + ret = sun8i_get_ephy_nodes(priv); + if (ret) + return ret; } priv->interface = pdata->phy_interface; diff --git a/drivers/net/ti/davinci_emac.c b/drivers/net/ti/davinci_emac.c index bb879d8d4fe..9d539849739 100644 --- a/drivers/net/ti/davinci_emac.c +++ b/drivers/net/ti/davinci_emac.c @@ -816,55 +816,12 @@ int davinci_emac_initialize(void) phy_id |= tmp & 0x0000ffff; - switch (phy_id) { -#ifdef PHY_KSZ8873 - case PHY_KSZ8873: - sprintf(phy[i].name, "KSZ8873 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = ksz8873_init_phy; - phy[i].is_phy_connected = ksz8873_is_phy_connected; - phy[i].get_link_speed = ksz8873_get_link_speed; - phy[i].auto_negotiate = ksz8873_auto_negotiate; - break; -#endif -#ifdef PHY_LXT972 - case PHY_LXT972: - sprintf(phy[i].name, "LXT972 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = lxt972_init_phy; - phy[i].is_phy_connected = lxt972_is_phy_connected; - phy[i].get_link_speed = lxt972_get_link_speed; - phy[i].auto_negotiate = lxt972_auto_negotiate; - break; -#endif -#ifdef PHY_DP83848 - case PHY_DP83848: - sprintf(phy[i].name, "DP83848 @ 0x%02x", - active_phy_addr[i]); - phy[i].init = dp83848_init_phy; - phy[i].is_phy_connected = dp83848_is_phy_connected; - phy[i].get_link_speed = dp83848_get_link_speed; - phy[i].auto_negotiate = dp83848_auto_negotiate; - break; -#endif -#ifdef PHY_ET1011C - case PHY_ET1011C: - sprintf(phy[i].name, "ET1011C @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = et1011c_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - break; -#endif - default: - sprintf(phy[i].name, "GENERIC @ 0x%02x", - active_phy_addr[i]); - phy[i].init = gen_init_phy; - phy[i].is_phy_connected = gen_is_phy_connected; - phy[i].get_link_speed = gen_get_link_speed; - phy[i].auto_negotiate = gen_auto_negotiate; - } + sprintf(phy[i].name, "GENERIC @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = gen_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; debug("Ethernet PHY: %s\n", phy[i].name); |