diff --git a/arch/arm/dts/dra72-evm-revc.dts b/arch/arm/dts/dra72-evm-revc.dts index 5a1bb34f6b..bc814f1b4c 100644 --- a/arch/arm/dts/dra72-evm-revc.dts +++ b/arch/arm/dts/dra72-evm-revc.dts @@ -67,7 +67,7 @@ ti,rx-internal-delay = ; ti,tx-internal-delay = ; ti,fifo-depth = ; - ti,min-output-imepdance; + ti,min-output-impedance; }; dp83867_1: ethernet-phy@3 { @@ -75,6 +75,6 @@ ti,rx-internal-delay = ; ti,tx-internal-delay = ; ti,fifo-depth = ; - ti,min-output-imepdance; + ti,min-output-impedance; }; }; diff --git a/common/fdt_support.c b/common/fdt_support.c index a57a5759e4..55d4d6f6d4 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -473,7 +473,7 @@ void fdt_fixup_ethernet(void *fdt) char *tmp, *end; char mac[16]; const char *path; - unsigned char mac_addr[6]; + unsigned char mac_addr[ARP_HLEN]; int offset; if (fdt_path_offset(fdt, "/aliases") < 0) diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig index ab7b9aa6aa..73df55d2de 100644 --- a/configs/am335x_evm_defconfig +++ b/configs/am335x_evm_defconfig @@ -58,3 +58,4 @@ CONFIG_G_DNL_VENDOR_NUM=0x0451 CONFIG_G_DNL_PRODUCT_NUM=0xd022 CONFIG_RSA=y CONFIG_SPL_OF_LIBFDT=y +CONFIG_PHY_MSCC=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f52629fa53..078d5a84f1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1,3 +1,5 @@ +source "drivers/net/phy/Kconfig" + config DM_ETH bool "Enable Driver Model for Ethernet drivers" depends on DM @@ -8,32 +10,6 @@ config DM_ETH This is currently implemented in net/eth.c Look in include/net.h for details. -config PHYLIB - bool "Ethernet PHY (physical media interface) support" - help - Enable Ethernet PHY (physical media interface) support. - -config RTL8211X_PHY_FORCE_MASTER - bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode" - depends on PHYLIB - help - Force master mode for 1000BASE-T on RTl8211x PHYs (except for RTL8211F). - This can work around link stability and data corruption issues on gigabit - links which can occur in slave mode on certain PHYs, e.g. on the - RTL8211C(L). - - Please note that two directly connected devices (i.e. via crossover cable) - will not be able to establish a link between each other if they both force - master mode. Multiple devices forcing master mode when connected by a - network switch do not pose a problem as the switch configures its affected - ports into slave mode. - - This option only affects gigabit links. If you must establish a direct - connection between two devices which both force master mode, try forcing - the link speed to 100MBit/s. - - If unsure, say N. - menuconfig NETDEVICES bool "Network device support" depends on NET @@ -155,6 +131,16 @@ config MVPP2 This driver supports the network interface units in the Marvell ARMADA 375 SoC. +config MACB + bool "Cadence MACB/GEM Ethernet Interface" + depends on DM_ETH + select PHYLIB + help + The Cadence MACB ethernet interface is found on many Atmel + AT91 and SAMA5 parts. This driver also supports the Cadence + GEM (Gigabit Ethernet MAC) found in some ARM SoC devices. + Say Y to include support for the MACB/GEM chip. + config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCI diff --git a/drivers/net/designware.c b/drivers/net/designware.c index eee4e09d7e..f9fb8e0886 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -764,6 +764,7 @@ static const struct udevice_id designware_eth_ids[] = { { .compatible = "allwinner,sun7i-a20-gmac" }, { .compatible = "altr,socfpga-stmmac" }, { .compatible = "amlogic,meson6-dwmac" }, + { .compatible = "amlogic,meson-gx-dwmac" }, { .compatible = "st,stm32-dwmac" }, { } }; diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 5f34c8fe3c..910879ba3e 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -1240,7 +1240,6 @@ static int fecmxc_probe(struct udevice *dev) } fec_reg_setup(priv); - fec_set_dev_name((char *)dev->name, dev_id); priv->dev_id = (dev_id == -1) ? 0 : dev_id; return 0; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 452fc3e3b9..1c4bef97b6 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include /* @@ -112,6 +113,7 @@ struct macb_device { struct mii_dev *bus; #ifdef CONFIG_DM_ETH + unsigned long pclk_rate; phy_interface_t phy_interface; #endif }; @@ -754,7 +756,11 @@ static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) static u32 macb_mdc_clk_div(int id, struct macb_device *macb) { u32 config; +#ifdef CONFIG_DM_ETH + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = MACB_BF(CLK, MACB_CLK_DIV8); @@ -771,7 +777,12 @@ static u32 macb_mdc_clk_div(int id, struct macb_device *macb) static u32 gem_mdc_clk_div(int id, struct macb_device *macb) { u32 config; + +#ifdef CONFIG_DM_ETH + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = GEM_BF(CLK, GEM_CLK_DIV8); @@ -991,13 +1002,36 @@ static const struct eth_ops macb_eth_ops = { .write_hwaddr = macb_write_hwaddr, }; +static int macb_enable_clk(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return -EINVAL; + + ret = clk_enable(&clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) + return -EINVAL; + + macb->pclk_rate = clk_rate; + + return 0; +} + static int macb_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct macb_device *macb = dev_get_priv(dev); - -#ifdef CONFIG_DM_ETH const char *phy_mode; + int ret; phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); @@ -1007,11 +1041,15 @@ static int macb_eth_probe(struct udevice *dev) debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); return -EINVAL; } -#endif macb->regs = (void *)pdata->iobase; + ret = macb_enable_clk(dev); + if (ret) + return ret; + _macb_eth_initialize(macb); + #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) int retval; struct mii_dev *mdiodev = mdio_alloc(); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig new file mode 100644 index 0000000000..1d514e92d3 --- /dev/null +++ b/drivers/net/phy/Kconfig @@ -0,0 +1,93 @@ + +config BITBANGMII + bool "Bit-banged ethernet MII management channel support" + +config MV88E6352_SWITCH + bool "Marvell 88E6352 switch support" + +menuconfig PHYLIB + bool "Ethernet PHY (physical media interface) support" + help + Enable Ethernet PHY (physical media interface) support. + +if PHYLIB + +config MV88E61XX_SWITCH + bool "Marvel MV88E61xx Ethernet switch PHY support." + +config PHYLIB_10G + bool "Generic 10G PHY support" + +config PHY_AQUANTIA + bool "Aquantia Ethernet PHYs support" + +config PHY_ATHEROS + bool "Atheros Ethernet PHYs support" + +config PHY_BROADCOM + bool "Broadcom Ethernet PHYs support" + +config PHY_CORTINA + bool "Cortina Ethernet PHYs support" + +config PHY_DAVICOM + bool "Davicom Ethernet PHYs support" + +config PHY_ET1011C + bool "LSI TruePHY ET1011C support" + +config PHY_LXT + bool "LXT971 Ethernet PHY support" + +config PHY_MARVELL + bool "Marvell Ethernet PHYs support" + +config PHY_MICREL + bool "Micrel Ethernet PHYs support" + +config PHY_MSCC + bool "Microsemi Corp Ethernet PHYs support" + +config PHY_NATSEMI + bool "National Semiconductor Ethernet PHYs support" + +config PHY_REALTEK + bool "Realtek Ethernet PHYs support" + +config RTL8211X_PHY_FORCE_MASTER + bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode" + depends on PHY_REALTEK + help + Force master mode for 1000BASE-T on RTl8211x PHYs (except for RTL8211F). + This can work around link stability and data corruption issues on gigabit + links which can occur in slave mode on certain PHYs, e.g. on the + RTL8211C(L). + + Please note that two directly connected devices (i.e. via crossover cable) + will not be able to establish a link between each other if they both force + master mode. Multiple devices forcing master mode when connected by a + network switch do not pose a problem as the switch configures its affected + ports into slave mode. + + This option only affects gigabit links. If you must establish a direct + connection between two devices which both force master mode, try forcing + the link speed to 100MBit/s. + + If unsure, say N. + +config PHY_SMSC + bool "Microchip(SMSC) Ethernet PHYs support" + +config PHY_TERANETICS + bool "Teranetics Ethernet PHYs support" + +config PHY_TI + bool "Texas Instruments Ethernet PHYs support" + +config PHY_VITESSE + bool "Vitesse Ethernet PHYs support" + +config PHY_XILINX + bool "Xilinx Ethernet PHYs support" + +endif #PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 1e299b97b9..d37297122a 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_PHY_TERANETICS) += teranetics.o obj-$(CONFIG_PHY_TI) += ti.o obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o obj-$(CONFIG_PHY_VITESSE) += vitesse.o +obj-$(CONFIG_PHY_MSCC) += mscc.o diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index c3058a40b2..ab0c44354c 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -82,6 +82,21 @@ #define MIIM_88E1310_PHY_RGMII_CTRL 21 #define MIIM_88E1310_PHY_PAGE 22 +/* 88E151x PHY defines */ +/* Page 3 registers */ +#define MIIM_88E151x_LED_FUNC_CTRL 16 +#define MIIM_88E151x_LED_FLD_SZ 4 +#define MIIM_88E151x_LED0_OFFS (0 * MIIM_88E151x_LED_FLD_SZ) +#define MIIM_88E151x_LED1_OFFS (1 * MIIM_88E151x_LED_FLD_SZ) +#define MIIM_88E151x_LED0_ACT 3 +#define MIIM_88E151x_LED1_100_1000_LINK 6 +#define MIIM_88E151x_LED_TIMER_CTRL 18 +#define MIIM_88E151x_INT_EN_OFFS 7 +/* Page 18 registers */ +#define MIIM_88E151x_GENERAL_CTRL 20 +#define MIIM_88E151x_MODE_SGMII 1 +#define MIIM_88E151x_RESET_OFFS 15 + /* Marvell 88E1011S */ static int m88e1011s_config(struct phy_device *phydev) { @@ -177,10 +192,7 @@ static int m88e1111s_config(struct phy_device *phydev) { int reg; - if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { + if (phy_interface_is_rgmii(phydev)) { reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_CR); if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || @@ -289,7 +301,7 @@ static int m88e1518_config(struct phy_device *phydev) */ /* EEE initialization */ - phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x00ff); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28); @@ -298,21 +310,23 @@ static int m88e1518_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D); phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C); phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159); - phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* Select page 18 */ - phy_write(phydev, MDIO_DEVAD_NONE, 22, 18); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 18); /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ - m88e1518_phy_writebits(phydev, 20, 0, 3, 1); + m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, + 0, 3, MIIM_88E151x_MODE_SGMII); /* PHY reset is necessary after changing MODE[2:0] */ - m88e1518_phy_writebits(phydev, 20, 15, 1, 1); + m88e1518_phy_writebits(phydev, MIIM_88E151x_GENERAL_CTRL, + MIIM_88E151x_RESET_OFFS, 1, 1); /* Reset page selection */ - phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0); udelay(100); } @@ -324,17 +338,25 @@ static int m88e1518_config(struct phy_device *phydev) static int m88e1510_config(struct phy_device *phydev) { /* Select page 3 */ - phy_write(phydev, MDIO_DEVAD_NONE, 22, 3); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, + MIIM_88E1118_PHY_LED_PAGE); /* Enable INTn output on LED[2] */ - m88e1518_phy_writebits(phydev, 18, 7, 1, 1); + m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_TIMER_CTRL, + MIIM_88E151x_INT_EN_OFFS, 1, 1); /* Configure LEDs */ - m88e1518_phy_writebits(phydev, 16, 0, 4, 3); /* LED[0]:0011 (ACT) */ - m88e1518_phy_writebits(phydev, 16, 4, 4, 6); /* LED[1]:0110 (LINK) */ + /* LED[0]:0011 (ACT) */ + m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL, + MIIM_88E151x_LED0_OFFS, MIIM_88E151x_LED_FLD_SZ, + MIIM_88E151x_LED0_ACT); + /* LED[1]:0110 (LINK 100/1000 Mbps) */ + m88e1518_phy_writebits(phydev, MIIM_88E151x_LED_FUNC_CTRL, + MIIM_88E151x_LED1_OFFS, MIIM_88E151x_LED_FLD_SZ, + MIIM_88E151x_LED1_100_1000_LINK); /* Reset page selection */ - phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0); return m88e1518_config(phydev); } @@ -596,17 +618,22 @@ static struct phy_driver M88E1149S_driver = { static struct phy_driver M88E1510_driver = { .name = "Marvell 88E1510", .uid = 0x1410dd0, - .mask = 0xffffff0, + .mask = 0xfffffff, .features = PHY_GBIT_FEATURES, .config = &m88e1510_config, .startup = &m88e1011s_startup, .shutdown = &genphy_shutdown, }; +/* + * This supports: + * 88E1518, uid 0x1410dd1 + * 88E1512, uid 0x1410dd4 + */ static struct phy_driver M88E1518_driver = { .name = "Marvell 88E1518", - .uid = 0x1410dd1, - .mask = 0xffffff0, + .uid = 0x1410dd0, + .mask = 0xffffffa, .features = PHY_GBIT_FEATURES, .config = &m88e1518_config, .startup = &m88e1011s_startup, diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c new file mode 100644 index 0000000000..439f5e3c5c --- /dev/null +++ b/drivers/net/phy/mscc.c @@ -0,0 +1,508 @@ +/* + * Microsemi PHY drivers + * + * SPDX-License-Identifier: The MIT License (MIT) + * + * Copyright (c) 2016 Microsemi Corporation + * + * Author: John Haechten + * + */ + +#include +#include + +/* Microsemi PHY ID's */ +#define PHY_ID_VSC8530 0x00070560 +#define PHY_ID_VSC8531 0x00070570 +#define PHY_ID_VSC8540 0x00070760 +#define PHY_ID_VSC8541 0x00070770 + +/* Microsemi VSC85xx PHY Register Pages */ +#define MSCC_EXT_PAGE_ACCESS 31 /* Page Access Register */ +#define MSCC_PHY_PAGE_STD 0x0000 /* Standard registers */ +#define MSCC_PHY_PAGE_EXT1 0x0001 /* Extended registers - page 1 */ +#define MSCC_PHY_PAGE_EXT2 0x0002 /* Extended registers - page 2 */ +#define MSCC_PHY_PAGE_EXT3 0x0003 /* Extended registers - page 3 */ +#define MSCC_PHY_PAGE_EXT4 0x0004 /* Extended registers - page 4 */ +#define MSCC_PHY_PAGE_GPIO 0x0010 /* GPIO registers */ +#define MSCC_PHY_PAGE_TEST 0x2A30 /* TEST Page registers */ +#define MSCC_PHY_PAGE_TR 0x52B5 /* Token Ring Page registers */ + +/* Std Page Register 28 - PHY AUX Control/Status */ +#define MIIM_AUX_CNTRL_STAT_REG 28 +#define MIIM_AUX_CNTRL_STAT_ACTIPHY_TO (0x0004) +#define MIIM_AUX_CNTRL_STAT_F_DUPLEX (0x0020) +#define MIIM_AUX_CNTRL_STAT_SPEED_MASK (0x0018) +#define MIIM_AUX_CNTRL_STAT_SPEED_POS (3) +#define MIIM_AUX_CNTRL_STAT_SPEED_10M (0x0) +#define MIIM_AUX_CNTRL_STAT_SPEED_100M (0x1) +#define MIIM_AUX_CNTRL_STAT_SPEED_1000M (0x2) + +/* Std Page Register 23 - Extended PHY CTRL_1 */ +#define MSCC_PHY_EXT_PHY_CNTL_1_REG 23 +#define MAC_IF_SELECTION_MASK (0x1800) +#define MAC_IF_SELECTION_GMII (0) +#define MAC_IF_SELECTION_RMII (1) +#define MAC_IF_SELECTION_RGMII (2) +#define MAC_IF_SELECTION_POS (11) +#define MAC_IF_SELECTION_WIDTH (2) + +/* Extended Page 2 Register 20E2 */ +#define MSCC_PHY_RGMII_CNTL_REG 20 +#define VSC_FAST_LINK_FAIL2_ENA_MASK (0x8000) +#define RX_CLK_OUT_MASK (0x0800) +#define RX_CLK_OUT_POS (11) +#define RX_CLK_OUT_WIDTH (1) +#define RX_CLK_OUT_NORMAL (0) +#define RX_CLK_OUT_DISABLE (1) +#define RGMII_RX_CLK_DELAY_POS (4) +#define RGMII_RX_CLK_DELAY_WIDTH (3) +#define RGMII_RX_CLK_DELAY_MASK (0x0070) +#define RGMII_TX_CLK_DELAY_POS (0) +#define RGMII_TX_CLK_DELAY_WIDTH (3) +#define RGMII_TX_CLK_DELAY_MASK (0x0007) + +/* Extended Page 2 Register 27E2 */ +#define MSCC_PHY_WOL_MAC_CONTROL 27 +#define EDGE_RATE_CNTL_POS (5) +#define EDGE_RATE_CNTL_WIDTH (3) +#define EDGE_RATE_CNTL_MASK (0x00E0) +#define RMII_CLK_OUT_ENABLE_POS (4) +#define RMII_CLK_OUT_ENABLE_WIDTH (1) +#define RMII_CLK_OUT_ENABLE_MASK (0x10) + +/* Token Ring Page 0x52B5 Registers */ +#define MSCC_PHY_REG_TR_ADDR_16 16 +#define MSCC_PHY_REG_TR_DATA_17 17 +#define MSCC_PHY_REG_TR_DATA_18 18 + +/* Token Ring - Read Value in */ +#define MSCC_PHY_TR_16_READ (0xA000) +/* Token Ring - Write Value out */ +#define MSCC_PHY_TR_16_WRITE (0x8000) + +/* Token Ring Registers */ +#define MSCC_PHY_TR_LINKDETCTRL_POS (3) +#define MSCC_PHY_TR_LINKDETCTRL_WIDTH (2) +#define MSCC_PHY_TR_LINKDETCTRL_VAL (3) +#define MSCC_PHY_TR_LINKDETCTRL_MASK (0x0018) +#define MSCC_PHY_TR_LINKDETCTRL_ADDR (0x07F8) + +#define MSCC_PHY_TR_VGATHRESH100_POS (0) +#define MSCC_PHY_TR_VGATHRESH100_WIDTH (7) +#define MSCC_PHY_TR_VGATHRESH100_VAL (0x0018) +#define MSCC_PHY_TR_VGATHRESH100_MASK (0x007f) +#define MSCC_PHY_TR_VGATHRESH100_ADDR (0x0FA4) + +#define MSCC_PHY_TR_VGAGAIN10_U_POS (0) +#define MSCC_PHY_TR_VGAGAIN10_U_WIDTH (1) +#define MSCC_PHY_TR_VGAGAIN10_U_MASK (0x0001) +#define MSCC_PHY_TR_VGAGAIN10_U_VAL (0) + +#define MSCC_PHY_TR_VGAGAIN10_L_POS (12) +#define MSCC_PHY_TR_VGAGAIN10_L_WIDTH (4) +#define MSCC_PHY_TR_VGAGAIN10_L_MASK (0xf000) +#define MSCC_PHY_TR_VGAGAIN10_L_VAL (0x0001) +#define MSCC_PHY_TR_VGAGAIN10_ADDR (0x0F92) + +/* General Timeout Values */ +#define MSCC_PHY_RESET_TIMEOUT (100) +#define MSCC_PHY_MICRO_TIMEOUT (500) + +/* RGMII/GMII Clock Delay (Skew) Options */ enum vsc_phy_rgmii_skew { + VSC_PHY_RGMII_DELAY_200_PS, + VSC_PHY_RGMII_DELAY_800_PS, + VSC_PHY_RGMII_DELAY_1100_PS, + VSC_PHY_RGMII_DELAY_1700_PS, + VSC_PHY_RGMII_DELAY_2000_PS, + VSC_PHY_RGMII_DELAY_2300_PS, + VSC_PHY_RGMII_DELAY_2600_PS, + VSC_PHY_RGMII_DELAY_3400_PS, +}; + +/* MAC i/f Clock Edge Rage Control (Slew), See Reg27E2 */ enum +vsc_phy_clk_slew { + VSC_PHY_CLK_SLEW_RATE_0, + VSC_PHY_CLK_SLEW_RATE_1, + VSC_PHY_CLK_SLEW_RATE_2, + VSC_PHY_CLK_SLEW_RATE_3, + VSC_PHY_CLK_SLEW_RATE_4, + VSC_PHY_CLK_SLEW_RATE_5, + VSC_PHY_CLK_SLEW_RATE_6, + VSC_PHY_CLK_SLEW_RATE_7, +}; + + +static int mscc_vsc8531_vsc8541_init_scripts(struct phy_device *phydev) +{ + u16 reg_val; + + /* Set to Access Token Ring Registers */ + phy_write(phydev, MDIO_DEVAD_NONE, + MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_TR); + + /* Update LinkDetectCtrl default to optimized values */ + /* Determined during Silicon Validation Testing */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_READ)); + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17); + reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_LINKDETCTRL_POS, + MSCC_PHY_TR_LINKDETCTRL_WIDTH, + MSCC_PHY_TR_LINKDETCTRL_VAL); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_LINKDETCTRL_ADDR | MSCC_PHY_TR_16_WRITE)); + + /* Update VgaThresh100 defaults to optimized values */ + /* Determined during Silicon Validation Testing */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_READ)); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18); + reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGATHRESH100_POS, + MSCC_PHY_TR_VGATHRESH100_WIDTH, + MSCC_PHY_TR_VGATHRESH100_VAL); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_VGATHRESH100_ADDR | MSCC_PHY_TR_16_WRITE)); + + /* Update VgaGain10 defaults to optimized values */ + /* Determined during Silicon Validation Testing */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_READ)); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18); + reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_U_POS, + MSCC_PHY_TR_VGAGAIN10_U_WIDTH, + MSCC_PHY_TR_VGAGAIN10_U_VAL); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_18, reg_val); + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17); + reg_val = bitfield_replace(reg_val, MSCC_PHY_TR_VGAGAIN10_L_POS, + MSCC_PHY_TR_VGAGAIN10_L_WIDTH, + MSCC_PHY_TR_VGAGAIN10_L_VAL); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_DATA_17, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_REG_TR_ADDR_16, + (MSCC_PHY_TR_VGAGAIN10_ADDR | MSCC_PHY_TR_16_WRITE)); + + /* Set back to Access Standard Page Registers */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return 0; +} + +static int mscc_parse_status(struct phy_device *phydev) +{ + u16 speed; + u16 mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_AUX_CNTRL_STAT_REG); + + if (mii_reg & MIIM_AUX_CNTRL_STAT_F_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_AUX_CNTRL_STAT_SPEED_MASK; + speed = speed >> MIIM_AUX_CNTRL_STAT_SPEED_POS; + + switch (speed) { + case MIIM_AUX_CNTRL_STAT_SPEED_1000M: + phydev->speed = SPEED_1000; + break; + case MIIM_AUX_CNTRL_STAT_SPEED_100M: + phydev->speed = SPEED_100; + break; + case MIIM_AUX_CNTRL_STAT_SPEED_10M: + phydev->speed = SPEED_10; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int mscc_startup(struct phy_device *phydev) +{ + int retval; + + retval = genphy_update_link(phydev); + + if (retval) + return retval; + + return mscc_parse_status(phydev); +} + +static int mscc_phy_soft_reset(struct phy_device *phydev) +{ + int retval = 0; + u16 timeout = MSCC_PHY_RESET_TIMEOUT; + u16 reg_val = 0; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (reg_val | BMCR_RESET)); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + while ((reg_val & BMCR_RESET) && (timeout > 0)) { + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + timeout--; + udelay(1000); /* 1 ms */ + } + + if (timeout == 0) { + printf("MSCC PHY Soft_Reset Error: mac i/f = 0x%x\n", + phydev->interface); + retval = -ETIME; + } + + return retval; +} + +static int vsc8531_vsc8541_mac_config(struct phy_device *phydev) +{ + u16 reg_val = 0; + u16 mac_if = 0; + u16 rx_clk_out = 0; + + /* For VSC8530/31 the only MAC modes are RMII/RGMII. */ + /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */ + /* Setup MAC Configuration */ + switch (phydev->interface) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + /* Set Reg23.12:11=0 */ + mac_if = MAC_IF_SELECTION_GMII; + /* Set Reg20E2.11=1 */ + rx_clk_out = RX_CLK_OUT_DISABLE; + break; + + case PHY_INTERFACE_MODE_RMII: + /* Set Reg23.12:11=1 */ + mac_if = MAC_IF_SELECTION_RMII; + /* Set Reg20E2.11=0 */ + rx_clk_out = RX_CLK_OUT_NORMAL; + break; + + case PHY_INTERFACE_MODE_RGMII: + /* Set Reg23.12:11=2 */ + mac_if = MAC_IF_SELECTION_RGMII; + /* Set Reg20E2.11=0 */ + rx_clk_out = RX_CLK_OUT_NORMAL; + break; + + default: + printf("MSCC PHY - INVALID MAC i/f Config: mac i/f = 0x%x\n", + phydev->interface); + return -EINVAL; + } + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, + MSCC_PHY_EXT_PHY_CNTL_1_REG); + /* Set MAC i/f bits Reg23.12:11 */ + reg_val = bitfield_replace(reg_val, MAC_IF_SELECTION_POS, + MAC_IF_SELECTION_WIDTH, mac_if); + /* Update Reg23.12:11 */ + phy_write(phydev, MDIO_DEVAD_NONE, + MSCC_PHY_EXT_PHY_CNTL_1_REG, reg_val); + /* Setup ExtPg_2 Register Access */ + phy_write(phydev, MDIO_DEVAD_NONE, + MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXT2); + /* Read Reg20E2 */ + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, + MSCC_PHY_RGMII_CNTL_REG); + reg_val = bitfield_replace(reg_val, RX_CLK_OUT_POS, + RX_CLK_OUT_WIDTH, rx_clk_out); + /* Update Reg20E2.11 */ + phy_write(phydev, MDIO_DEVAD_NONE, + MSCC_PHY_RGMII_CNTL_REG, reg_val); + /* Before leaving - Change back to Std Page Register Access */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return 0; +} + +static int vsc8531_config(struct phy_device *phydev) +{ + int retval = -EINVAL; + u16 reg_val; + u16 rmii_clk_out; + enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS; + enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS; + enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4; + + /* For VSC8530/31 and VSC8540/41 the init scripts are the same */ + mscc_vsc8531_vsc8541_init_scripts(phydev); + + /* For VSC8530/31 the only MAC modes are RMII/RGMII. */ + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_RGMII: + retval = vsc8531_vsc8541_mac_config(phydev); + if (retval != 0) + return retval; + + retval = mscc_phy_soft_reset(phydev); + if (retval != 0) + return retval; + break; + default: + printf("PHY 8530/31 MAC i/f Config Error: mac i/f = 0x%x\n", + phydev->interface); + return -EINVAL; + } + /* Default RMII Clk Output to 0=OFF/1=ON */ + rmii_clk_out = 0; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXT2); + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG); + + /* Reg20E2 - Update RGMII RX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS, + RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew); + /* Reg20E2 - Update RGMII TX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS, + RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew); + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL); + /* Reg27E2 - Update Clk Slew Rate. */ + reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS, + EDGE_RATE_CNTL_WIDTH, edge_rate); + /* Reg27E2 - Update RMII Clk Out. */ + reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS, + RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out); + /* Update Reg27E2 */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return genphy_config_aneg(phydev); +} + +static int vsc8541_config(struct phy_device *phydev) +{ + int retval = -EINVAL; + u16 reg_val; + u16 rmii_clk_out; + enum vsc_phy_rgmii_skew rx_clk_skew = VSC_PHY_RGMII_DELAY_1700_PS; + enum vsc_phy_rgmii_skew tx_clk_skew = VSC_PHY_RGMII_DELAY_800_PS; + enum vsc_phy_clk_slew edge_rate = VSC_PHY_CLK_SLEW_RATE_4; + + /* For VSC8530/31 and VSC8540/41 the init scripts are the same */ + mscc_vsc8531_vsc8541_init_scripts(phydev); + + /* For VSC8540/41 the only MAC modes are (G)MII and RMII/RGMII. */ + switch (phydev->interface) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_RGMII: + retval = vsc8531_vsc8541_mac_config(phydev); + if (retval != 0) + return retval; + + retval = mscc_phy_soft_reset(phydev); + if (retval != 0) + return retval; + break; + default: + printf("PHY 8541 MAC i/f config Error: mac i/f = 0x%x\n", + phydev->interface); + return -EINVAL; + } + /* Default RMII Clk Output to 0=OFF/1=ON */ + rmii_clk_out = 0; + + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_EXT2); + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG); + /* Reg20E2 - Update RGMII RX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_RX_CLK_DELAY_POS, + RGMII_RX_CLK_DELAY_WIDTH, rx_clk_skew); + /* Reg20E2 - Update RGMII TX_Clk Skews. */ + reg_val = bitfield_replace(reg_val, RGMII_TX_CLK_DELAY_POS, + RGMII_TX_CLK_DELAY_WIDTH, tx_clk_skew); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_RGMII_CNTL_REG, reg_val); + + reg_val = phy_read(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL); + /* Reg27E2 - Update Clk Slew Rate. */ + reg_val = bitfield_replace(reg_val, EDGE_RATE_CNTL_POS, + EDGE_RATE_CNTL_WIDTH, edge_rate); + /* Reg27E2 - Update RMII Clk Out. */ + reg_val = bitfield_replace(reg_val, RMII_CLK_OUT_ENABLE_POS, + RMII_CLK_OUT_ENABLE_WIDTH, rmii_clk_out); + /* Update Reg27E2 */ + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_PHY_WOL_MAC_CONTROL, reg_val); + phy_write(phydev, MDIO_DEVAD_NONE, MSCC_EXT_PAGE_ACCESS, + MSCC_PHY_PAGE_STD); + + return genphy_config_aneg(phydev); +} + +static struct phy_driver VSC8530_driver = { + .name = "Microsemi VSC8530", + .uid = PHY_ID_VSC8530, + .mask = 0x000ffff0, + .features = PHY_BASIC_FEATURES, + .config = &vsc8531_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8531_driver = { + .name = "Microsemi VSC8531", + .uid = PHY_ID_VSC8531, + .mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8531_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8540_driver = { + .name = "Microsemi VSC8540", + .uid = PHY_ID_VSC8540, + .mask = 0x000ffff0, + .features = PHY_BASIC_FEATURES, + .config = &vsc8541_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8541_driver = { + .name = "Microsemi VSC8541", + .uid = PHY_ID_VSC8541, + .mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8541_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_mscc_init(void) +{ + phy_register(&VSC8530_driver); + phy_register(&VSC8531_driver); + phy_register(&VSC8540_driver); + phy_register(&VSC8541_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 80bdfb6d9d..8db65749b1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -512,6 +512,9 @@ int phy_init(void) #ifdef CONFIG_PHY_XILINX phy_xilinx_init(); #endif +#ifdef CONFIG_PHY_MSCC + phy_mscc_init(); +#endif return 0; } diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index d1ce4060ff..1d870806a3 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -27,6 +27,7 @@ DECLARE_GLOBAL_DATA_PTR; /* Extended Registers */ #define DP83867_RGMIICTL 0x0032 #define DP83867_RGMIIDCTL 0x0086 +#define DP83867_IO_MUX_CFG 0x0170 #define DP83867_SW_RESET BIT(15) #define DP83867_SW_RESTART BIT(14) @@ -84,10 +85,17 @@ DECLARE_GLOBAL_DATA_PTR; #define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS #define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB +/* IO_MUX_CFG bits */ +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f + +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 +#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f + struct dp83867_private { int rx_id_delay; int tx_id_delay; int fifo_depth; + int io_impedance; }; /** @@ -166,6 +174,15 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; struct udevice *dev = phydev->dev; + int node = dev->of_offset; + const void *fdt = gd->fdt_blob; + + if (fdtdec_get_bool(fdt, node, "ti,max-output-impedance")) + dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; + else if (fdtdec_get_bool(fdt, node, "ti,min-output-impedance")) + dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN; + else + dp83867->io_impedance = -EINVAL; dp83867->rx_id_delay = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "ti,rx-internal-delay", -1); @@ -186,6 +203,7 @@ static int dp83867_of_init(struct phy_device *phydev) dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY; dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY; dp83867->fifo_depth = DEFAULT_FIFO_DEPTH; + dp83867->io_impedance = -EINVAL; return 0; } @@ -246,8 +264,7 @@ static int dp83867_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0); } - if ((phydev->interface >= PHY_INTERFACE_MODE_RGMII_ID) && - (phydev->interface <= PHY_INTERFACE_MODE_RGMII_RXID)) { + if (phy_interface_is_rgmii(phydev)) { val = phy_read_mmd_indirect(phydev, DP83867_RGMIICTL, DP83867_DEVADDR, phydev->addr); @@ -269,6 +286,19 @@ static int dp83867_config(struct phy_device *phydev) phy_write_mmd_indirect(phydev, DP83867_RGMIIDCTL, DP83867_DEVADDR, phydev->addr, delay); + + if (dp83867->io_impedance >= 0) { + val = phy_read_mmd_indirect(phydev, + DP83867_IO_MUX_CFG, + DP83867_DEVADDR, + phydev->addr); + 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); + } } genphy_config_aneg(phydev); diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index a077b98d8c..e5e9922b30 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -127,9 +127,7 @@ static int cis8204_config(struct phy_device *phydev) genphy_config_aneg(phydev); - if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || - (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) + if (phy_interface_is_rgmii(phydev)) phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII); diff --git a/include/net.h b/include/net.h index 1f4d947350..ed5259a807 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,14 @@ #define PKTALIGN ARCH_DMA_MINALIGN +/* ARP hardware address length */ +#define ARP_HLEN 6 +/* + * The size of a MAC address in string form, each digit requires two chars + * and five separator characters to form '00:00:00:00:00:00'. + */ +#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) + /* IPv4 addresses are always 32 bits in size */ struct in_addr { __be32 s_addr; @@ -90,7 +98,7 @@ enum eth_state_t { */ struct eth_pdata { phys_addr_t iobase; - unsigned char enetaddr[6]; + unsigned char enetaddr[ARP_HLEN]; int phy_interface; int max_speed; }; @@ -160,8 +168,9 @@ void eth_halt_state_only(void); /* Set passive state */ #ifndef CONFIG_DM_ETH struct eth_device { - char name[16]; - unsigned char enetaddr[6]; +#define ETH_NAME_LEN 16 + char name[ETH_NAME_LEN]; + unsigned char enetaddr[ARP_HLEN]; phys_addr_t iobase; int state; @@ -300,9 +309,9 @@ u32 ether_crc(size_t len, unsigned char const *p); */ struct ethernet_hdr { - u8 et_dest[6]; /* Destination node */ - u8 et_src[6]; /* Source node */ - u16 et_protlen; /* Protocol or length */ + u8 et_dest[ARP_HLEN]; /* Destination node */ + u8 et_src[ARP_HLEN]; /* Source node */ + u16 et_protlen; /* Protocol or length */ }; /* Ethernet header size */ @@ -311,16 +320,16 @@ struct ethernet_hdr { #define ETH_FCS_LEN 4 /* Octets in the FCS */ struct e802_hdr { - u8 et_dest[6]; /* Destination node */ - u8 et_src[6]; /* Source node */ - u16 et_protlen; /* Protocol or length */ - u8 et_dsap; /* 802 DSAP */ - u8 et_ssap; /* 802 SSAP */ - u8 et_ctl; /* 802 control */ - u8 et_snap1; /* SNAP */ + u8 et_dest[ARP_HLEN]; /* Destination node */ + u8 et_src[ARP_HLEN]; /* Source node */ + u16 et_protlen; /* Protocol or length */ + u8 et_dsap; /* 802 DSAP */ + u8 et_ssap; /* 802 SSAP */ + u8 et_ctl; /* 802 control */ + u8 et_snap1; /* SNAP */ u8 et_snap2; u8 et_snap3; - u16 et_prot; /* 802 protocol */ + u16 et_prot; /* 802 protocol */ }; /* 802 + SNAP + ethernet header size */ @@ -330,11 +339,11 @@ struct e802_hdr { * Virtual LAN Ethernet header */ struct vlan_ethernet_hdr { - u8 vet_dest[6]; /* Destination node */ - u8 vet_src[6]; /* Source node */ - u16 vet_vlan_type; /* PROT_VLAN */ - u16 vet_tag; /* TAG of VLAN */ - u16 vet_type; /* protocol type */ + u8 vet_dest[ARP_HLEN]; /* Destination node */ + u8 vet_src[ARP_HLEN]; /* Source node */ + u16 vet_vlan_type; /* PROT_VLAN */ + u16 vet_tag; /* TAG of VLAN */ + u16 vet_type; /* protocol type */ }; /* VLAN Ethernet header size */ @@ -405,7 +414,6 @@ struct arp_hdr { # define ARP_ETHER 1 /* Ethernet hardware address */ u16 ar_pro; /* Format of protocol address */ u8 ar_hln; /* Length of hardware address */ -# define ARP_HLEN 6 u8 ar_pln; /* Length of protocol address */ # define ARP_PLEN 4 u16 ar_op; /* Operation */ @@ -514,16 +522,16 @@ extern char net_nis_domain[32]; /* Our IS domain */ extern char net_hostname[32]; /* Our hostname */ extern char net_root_path[64]; /* Our root path */ /** END OF BOOTP EXTENTIONS **/ -extern u8 net_ethaddr[6]; /* Our ethernet address */ -extern u8 net_server_ethaddr[6]; /* Boot server enet address */ +extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ +extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ extern uchar *net_tx_packet; /* THE transmit packet */ extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ extern uchar *net_rx_packet; /* Current receive packet */ extern int net_rx_packet_len; /* Current rx packet length */ -extern const u8 net_bcast_ethaddr[6]; /* Ethernet broadcast address */ -extern const u8 net_null_ethaddr[6]; +extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ +extern const u8 net_null_ethaddr[ARP_HLEN]; #define VLAN_NONE 4095 /* untagged */ #define VLAN_IDMASK 0x0fff /* mask of valid vlan id */ @@ -562,9 +570,9 @@ extern ushort cdp_appliance_vlan; /* CDP returned appliance VLAN */ */ static inline int is_cdp_packet(const uchar *ethaddr) { - extern const u8 net_cdp_ethaddr[6]; + extern const u8 net_cdp_ethaddr[ARP_HLEN]; - return memcmp(ethaddr, net_cdp_ethaddr, 6) == 0; + return memcmp(ethaddr, net_cdp_ethaddr, ARP_HLEN) == 0; } #endif diff --git a/include/phy.h b/include/phy.h index 268d9a1823..5477496e0e 100644 --- a/include/phy.h +++ b/include/phy.h @@ -266,6 +266,7 @@ int phy_teranetics_init(void); int phy_ti_init(void); int phy_vitesse_init(void); int phy_xilinx_init(void); +int phy_mscc_init(void); int board_phy_config(struct phy_device *phydev); int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id); diff --git a/include/u-boot/crc.h b/include/u-boot/crc.h index 754ac729ce..6764d58bab 100644 --- a/include/u-boot/crc.h +++ b/include/u-boot/crc.h @@ -9,6 +9,9 @@ #ifndef _UBOOT_CRC_H #define _UBOOT_CRC_H +/* lib/crc8.c */ +unsigned int crc8(unsigned int crc_start, const unsigned char *vptr, int len); + /* lib/crc32.c */ uint32_t crc32 (uint32_t, const unsigned char *, uint); uint32_t crc32_wd (uint32_t, const unsigned char *, uint, uint); diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 1d13011089..c3cc3152a2 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -230,7 +230,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, eth_write_hwaddr(dev); break; case env_op_delete: - memset(pdata->enetaddr, 0, 6); + memset(pdata->enetaddr, 0, ARP_HLEN); } } @@ -458,7 +458,7 @@ static int eth_post_probe(struct udevice *dev) { struct eth_device_priv *priv = dev->uclass_priv; struct eth_pdata *pdata = dev->platdata; - unsigned char env_enetaddr[6]; + unsigned char env_enetaddr[ARP_HLEN]; #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct eth_ops *ops = eth_get_ops(dev); @@ -497,17 +497,17 @@ static int eth_post_probe(struct udevice *dev) eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); if (!is_zero_ethaddr(env_enetaddr)) { if (!is_zero_ethaddr(pdata->enetaddr) && - memcmp(pdata->enetaddr, env_enetaddr, 6)) { + memcmp(pdata->enetaddr, env_enetaddr, ARP_HLEN)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); - printf("Address in SROM is %pM\n", + printf("Address in ROM is %pM\n", pdata->enetaddr); printf("Address in environment is %pM\n", env_enetaddr); } /* Override the ROM MAC address */ - memcpy(pdata->enetaddr, env_enetaddr, 6); + memcpy(pdata->enetaddr, env_enetaddr, ARP_HLEN); } else if (is_valid_ethaddr(pdata->enetaddr)) { eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); printf("\nWarning: %s using MAC address from ROM\n", @@ -535,7 +535,7 @@ static int eth_pre_remove(struct udevice *dev) eth_get_ops(dev)->stop(dev); /* clear the MAC address */ - memset(pdata->enetaddr, 0, 6); + memset(pdata->enetaddr, 0, ARP_HLEN); return 0; } diff --git a/net/eth_common.c b/net/eth_common.c index 288090155e..e9d3c66741 100644 --- a/net/eth_common.c +++ b/net/eth_common.c @@ -32,7 +32,7 @@ int eth_getenv_enetaddr(const char *name, uchar *enetaddr) int eth_setenv_enetaddr(const char *name, const uchar *enetaddr) { - char buf[20]; + char buf[ARP_HLEN_ASCII + 1]; sprintf(buf, "%pM", enetaddr); diff --git a/net/eth_legacy.c b/net/eth_legacy.c index 1354f49ec0..e4bd0f4c1a 100644 --- a/net/eth_legacy.c +++ b/net/eth_legacy.c @@ -121,7 +121,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, eth_write_hwaddr(dev, "eth", dev->index); break; case env_op_delete: - memset(dev->enetaddr, 0, 6); + memset(dev->enetaddr, 0, ARP_HLEN); } } dev = dev->next; @@ -134,14 +134,14 @@ U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr); int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { - unsigned char env_enetaddr[6]; + unsigned char env_enetaddr[ARP_HLEN]; int ret = 0; eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr); if (!is_zero_ethaddr(env_enetaddr)) { if (!is_zero_ethaddr(dev->enetaddr) && - memcmp(dev->enetaddr, env_enetaddr, 6)) { + memcmp(dev->enetaddr, env_enetaddr, ARP_HLEN)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); printf("Address in SROM is %pM\n", @@ -150,7 +150,7 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, env_enetaddr); } - memcpy(dev->enetaddr, env_enetaddr, 6); + memcpy(dev->enetaddr, env_enetaddr, ARP_HLEN); } else if (is_valid_ethaddr(dev->enetaddr)) { eth_setenv_enetaddr_by_index(base_name, eth_number, dev->enetaddr); @@ -299,7 +299,7 @@ int eth_initialize(void) */ int eth_mcast_join(struct in_addr mcast_ip, int join) { - u8 mcast_mac[6]; + u8 mcast_mac[ARP_HLEN]; if (!eth_current || !eth_current->mcast) return -1; mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff; diff --git a/tools/.gitignore b/tools/.gitignore index cb1e722d45..0d1f076d78 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -6,6 +6,7 @@ /fit_check_sign /fit_info /gen_eth_addr +/gen_ethaddr_crc /ifdtool /img2srec /kwboot diff --git a/tools/Makefile b/tools/Makefile index cbccd4ab91..5000f4d5bb 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -42,6 +42,10 @@ envcrc-objs := envcrc.o lib/crc32.o common/env_embedded.o lib/sha1.o hostprogs-$(CONFIG_CMD_NET) += gen_eth_addr HOSTCFLAGS_gen_eth_addr.o := -pedantic +hostprogs-$(CONFIG_CMD_NET) += gen_ethaddr_crc +gen_ethaddr_crc-objs := gen_ethaddr_crc.o lib/crc8.o +HOSTCFLAGS_gen_ethaddr_crc.o := -pedantic + hostprogs-$(CONFIG_CMD_LOADS) += img2srec HOSTCFLAGS_img2srec.o := -pedantic @@ -195,6 +199,7 @@ fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o # that won't build on some weird host compiler -- though there are lots of # exceptions for files that aren't complaint. HOSTCFLAGS_crc32.o := -pedantic +HOSTCFLAGS_crc8.o := -pedantic HOSTCFLAGS_md5.o := -pedantic HOSTCFLAGS_sha1.o := -pedantic HOSTCFLAGS_sha256.o := -pedantic diff --git a/tools/gen_ethaddr_crc.c b/tools/gen_ethaddr_crc.c new file mode 100644 index 0000000000..fe9896dca9 --- /dev/null +++ b/tools/gen_ethaddr_crc.c @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2016 + * Olliver Schinagl + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#define ARP_HLEN 6 /* Length of hardware address */ +#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) /* with separators */ +#define ARP_HLEN_LAZY (ARP_HLEN * 2) /* separatorless hardware address length */ + +uint8_t nibble_to_hex(const char *nibble, bool lo) +{ + return (strtol(nibble, NULL, 16) << (lo ? 0 : 4)) & (lo ? 0x0f : 0xf0); +} + +int process_mac(const char *mac_address) +{ + uint8_t ethaddr[ARP_HLEN + 1] = { 0x00 }; + uint_fast8_t i = 0; + + while (*mac_address != '\0') { + char nibble[2] = { 0x00, '\n' }; /* for strtol */ + + nibble[0] = *mac_address++; + if (isxdigit(nibble[0])) { + if (isupper(nibble[0])) + nibble[0] = tolower(nibble[0]); + ethaddr[i >> 1] |= nibble_to_hex(nibble, (i % 2) != 0); + i++; + } + } + + for (i = 0; i < ARP_HLEN; i++) + printf("%.2x", ethaddr[i]); + printf("%.2x\n", crc8(0, ethaddr, ARP_HLEN)); + + return 0; +} + +void print_usage(char *cmdname) +{ + printf("Usage: %s \n", cmdname); + puts(" may be with or without separators."); + puts("Valid seperators are ':' and '-'."); + puts(" digits are in base 16.\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + print_usage(argv[0]); + return 1; + } + + if (!((strlen(argv[1]) == ARP_HLEN_ASCII) || (strlen(argv[1]) == ARP_HLEN_LAZY))) { + puts("The MAC address is not valid.\n"); + print_usage(argv[0]); + return 1; + } + + if (process_mac(argv[1])) { + puts("Failed to calculate the MAC's checksum."); + return 1; + } + + return 0; +}