mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
commit
e1a71f8b33
23 changed files with 872 additions and 94 deletions
|
@ -67,7 +67,7 @@
|
|||
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
|
||||
ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
|
||||
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
|
||||
ti,min-output-imepdance;
|
||||
ti,min-output-impedance;
|
||||
};
|
||||
|
||||
dp83867_1: ethernet-phy@3 {
|
||||
|
@ -75,6 +75,6 @@
|
|||
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
|
||||
ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
|
||||
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
|
||||
ti,min-output-imepdance;
|
||||
ti,min-output-impedance;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
|
|
93
drivers/net/phy/Kconfig
Normal file
93
drivers/net/phy/Kconfig
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
508
drivers/net/phy/mscc.c
Normal file
508
drivers/net/phy/mscc.c
Normal file
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Microsemi PHY drivers
|
||||
*
|
||||
* SPDX-License-Identifier: The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Microsemi Corporation
|
||||
*
|
||||
* Author: John Haechten
|
||||
*
|
||||
*/
|
||||
|
||||
#include <miiphy.h>
|
||||
#include <bitfield.h>
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,8 +309,8 @@ 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 */
|
||||
u8 et_dest[ARP_HLEN]; /* Destination node */
|
||||
u8 et_src[ARP_HLEN]; /* Source node */
|
||||
u16 et_protlen; /* Protocol or length */
|
||||
};
|
||||
|
||||
|
@ -311,8 +320,8 @@ 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 */
|
||||
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 */
|
||||
|
@ -330,8 +339,8 @@ struct e802_hdr {
|
|||
* Virtual LAN Ethernet header
|
||||
*/
|
||||
struct vlan_ethernet_hdr {
|
||||
u8 vet_dest[6]; /* Destination node */
|
||||
u8 vet_src[6]; /* Source node */
|
||||
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 */
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
|
@ -6,6 +6,7 @@
|
|||
/fit_check_sign
|
||||
/fit_info
|
||||
/gen_eth_addr
|
||||
/gen_ethaddr_crc
|
||||
/ifdtool
|
||||
/img2srec
|
||||
/kwboot
|
||||
|
|
|
@ -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
|
||||
|
|
75
tools/gen_ethaddr_crc.c
Normal file
75
tools/gen_ethaddr_crc.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* (C) Copyright 2016
|
||||
* Olliver Schinagl <oliver@schinagl.nl>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
#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 <mac_address>\n", cmdname);
|
||||
puts("<mac_address> may be with or without separators.");
|
||||
puts("Valid seperators are ':' and '-'.");
|
||||
puts("<mac_address> 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;
|
||||
}
|
Loading…
Reference in a new issue