From ebcb40a5a02adc153db949d59e9df9bf0d89b6ec Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 2 Nov 2016 10:06:55 +0800 Subject: [PATCH 01/20] net: Kconfig: Add CONFIG_MACB option Add CONFIG_MACB option in KConfig to be used to select the Cadence MACB Ethernet driver. Signed-off-by: Wenyou Yang --- drivers/net/Kconfig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f52629fa53..1d31e238b6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -155,6 +155,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 From 577aa3b3587193ee078ce83d918604da6ac84dd5 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 2 Nov 2016 10:06:56 +0800 Subject: [PATCH 02/20] net: macb: Add the clock support Due to introducing the at91 clock driver, add the clock support. Signed-off-by: Wenyou Yang Acked-by: Joe Hershberger --- drivers/net/macb.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01527f7fc7..f97b82afdd 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,6 +1002,30 @@ 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); @@ -998,6 +1033,7 @@ static int macb_eth_probe(struct udevice *dev) #ifdef CONFIG_DM_ETH const char *phy_mode; + int ret; phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); if (phy_mode) @@ -1010,7 +1046,12 @@ static int macb_eth_probe(struct udevice *dev) 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(); From 6d2c1d26ee58b46f042b23af62209c2e1860bb24 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 2 Nov 2016 10:06:57 +0800 Subject: [PATCH 03/20] net: macb: Remove redundant #ifdef CONFIG_DM_ETH Remove the redundant #ifdef CONFIG_DM_ETH/#endif. Signed-off-by: Wenyou Yang Acked-by: Joe Hershberger --- drivers/net/macb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index f97b82afdd..67d820fefa 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1030,8 +1030,6 @@ 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; @@ -1042,7 +1040,6 @@ 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; From a40db6d511712f53b6663e61786a9eb825589984 Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:19 +0100 Subject: [PATCH 04/20] net: cosmetic: Do not use magic values for ARP_HLEN Commit 674bb249825a ("net: cosmetic: Replace magic numbers in arp.c with constants") introduced a nice define to replace the magic value 6 for the ethernet hardware address. Replace more hardcoded instances of 6 which really reference the ARP_HLEN (iow the MAC/Hardware/Ethernet address). Signed-off-by: Olliver Schinagl Acked-by: Joe Hershberger --- common/fdt_support.c | 2 +- include/net.h | 52 +++++++++++++++++++++++--------------------- net/eth-uclass.c | 10 ++++----- net/eth_legacy.c | 10 ++++----- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index c9f7019e38..f16039114a 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/include/net.h b/include/net.h index 1f4d947350..61568f6b31 100644 --- a/include/net.h +++ b/include/net.h @@ -38,6 +38,9 @@ #define PKTALIGN ARCH_DMA_MINALIGN +/* ARP hardware address length */ +#define ARP_HLEN 6 + /* IPv4 addresses are always 32 bits in size */ struct in_addr { __be32 s_addr; @@ -90,7 +93,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; }; @@ -161,7 +164,7 @@ void eth_halt_state_only(void); /* Set passive state */ #ifndef CONFIG_DM_ETH struct eth_device { char name[16]; - unsigned char enetaddr[6]; + unsigned char enetaddr[ARP_HLEN]; phys_addr_t iobase; int state; @@ -300,9 +303,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 +314,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 +333,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 +408,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 +516,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 +564,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/net/eth-uclass.c b/net/eth-uclass.c index 1d13011089..140e47d52d 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,7 +497,7 @@ 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", @@ -507,7 +507,7 @@ static int eth_post_probe(struct udevice *dev) } /* 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_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; From 9f455bcb34fcab31b0eb8eec5702105c8d4bde18 Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:20 +0100 Subject: [PATCH 05/20] net: cosmetic: Make the MAC address string less magical In u-boot printf has been extended with the %pM formatter to allow printing of MAC addresses. However buffers that want to store a MAC address cannot safely get the size. Add a define for this case so the string of a MAC address can be reliably obtained. Signed-off-by: Olliver Schinagl Acked-by: Joe Hershberger --- include/net.h | 5 +++++ net/eth_common.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/net.h b/include/net.h index 61568f6b31..c3bfb63782 100644 --- a/include/net.h +++ b/include/net.h @@ -40,6 +40,11 @@ /* 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 { 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); From 2c07c3299467e2313d6764ed28db62e8fcc77ccf Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:21 +0100 Subject: [PATCH 06/20] net: cosmetic: Define ethernet name length There are various places where the ethernet device name is defined to several different sizes. Lets add a define and start using it. Signed-off-by: Olliver Schinagl Acked-by: Joe Hershberger --- include/net.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net.h b/include/net.h index c3bfb63782..ed5259a807 100644 --- a/include/net.h +++ b/include/net.h @@ -168,7 +168,8 @@ void eth_halt_state_only(void); /* Set passive state */ #ifndef CONFIG_DM_ETH struct eth_device { - char name[16]; +#define ETH_NAME_LEN 16 + char name[ETH_NAME_LEN]; unsigned char enetaddr[ARP_HLEN]; phys_addr_t iobase; int state; From 26d40b0a17f86f748803f3c60926e614177117b7 Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:23 +0100 Subject: [PATCH 07/20] net: core: cosmetic: A MAC address is not limited to SROM Currently, we print that the MAC from the SROM does not match. It can be many forms of ROM, so lets drop the S. Signed-off-by: Olliver Schinagl Acked-by: Joe Hershberger --- net/eth-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 140e47d52d..c3cc3152a2 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -500,7 +500,7 @@ static int eth_post_probe(struct udevice *dev) 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); From 1d3c5392396726915558e95e08947e44d994d9bb Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:31 +0100 Subject: [PATCH 08/20] tools: Allow crc8 to be used This patch enables crc8 to be used from within the tools directory using u-boot/crc.h. Signed-off-by: Olliver Schinagl Reviewed-by: Joe Hershberger Signed-off-by: Olliver Schinagl --- include/u-boot/crc.h | 3 +++ tools/Makefile | 1 + 2 files changed, 4 insertions(+) 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/tools/Makefile b/tools/Makefile index f5ac6313e1..5e089c957e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -196,6 +196,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 From c25f01a63ac21ddfa522d972b09a0e9e5ab4b4cd Mon Sep 17 00:00:00 2001 From: "oliver@schinagl.nl" Date: Fri, 25 Nov 2016 16:30:32 +0100 Subject: [PATCH 09/20] tools: Add tool to add crc8 to a mac address This patch adds a little tool that takes a generic MAC address and generates a CRC byte for it. The output is the full MAC address without any separators, ready written into an EEPROM. Signed-off-by: Olliver Schinagl Signed-off-by: Olliver Schinagl Acked-by: Joe Hershberger --- tools/.gitignore | 1 + tools/Makefile | 4 +++ tools/gen_ethaddr_crc.c | 75 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 tools/gen_ethaddr_crc.c 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 5e089c957e..eca8ecce10 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -43,6 +43,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 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; +} From 8abdeadc5c48e79d0ff37cf2215654a7e6866704 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Fri, 9 Dec 2016 10:46:02 +0000 Subject: [PATCH 10/20] net: phy: ti: Fix dp83867 RGMII_TXID interface path There is code that is specifically for RGMII_TXID interface, but this will never get used because the code checks that the RGMII interface is RGMII_ID to RGMII_RXID; RGMII_TXID is after this. To fix this and avoid similar problems in the future, use the phy_interface_is_rgmii helper function. Signed-off-by: Phil Edworthy Acked-by: Joe Hershberger --- drivers/net/phy/ti.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index c55dd973f4..5e2b2dd9dd 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -246,8 +246,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); From 83cfbeb0df9f5962a16e8737e08cf59ed84e0cff Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 12 Dec 2016 12:54:13 +0000 Subject: [PATCH 11/20] net: phy: Fix mask so that we can identify Marvell 88E1518 The mask for the 88E1510 meant that the 88E1518 code would never be used. Signed-off-by: Phil Edworthy Reviewed-by: Stefan Roese Acked-by: Joe Hershberger --- drivers/net/phy/marvell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index c3058a40b2..ae870c592b 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -596,7 +596,7 @@ 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, @@ -606,7 +606,7 @@ static struct phy_driver M88E1510_driver = { static struct phy_driver M88E1518_driver = { .name = "Marvell 88E1518", .uid = 0x1410dd1, - .mask = 0xffffff0, + .mask = 0xfffffff, .features = PHY_GBIT_FEATURES, .config = &m88e1518_config, .startup = &m88e1011s_startup, From 998640b478ab67f30644eef1deda2c035b81dfe7 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 12 Dec 2016 12:54:14 +0000 Subject: [PATCH 12/20] net: phy: Add support for Marvell M88E1512 This device also works with the 88E1518 code, so we just adjust the UID mask accordingly. Signed-off-by: Phil Edworthy Acked-by: Joe Hershberger --- drivers/net/phy/marvell.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index ae870c592b..e76a14b47a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -603,10 +603,15 @@ static struct phy_driver M88E1510_driver = { .shutdown = &genphy_shutdown, }; +/* + * This supports: + * 88E1518, uid 0x1410dd1 + * 88E1512, uid 0x1410dd4 + */ static struct phy_driver M88E1518_driver = { .name = "Marvell 88E1518", - .uid = 0x1410dd1, - .mask = 0xfffffff, + .uid = 0x1410dd0, + .mask = 0xffffffa, .features = PHY_GBIT_FEATURES, .config = &m88e1518_config, .startup = &m88e1011s_startup, From 24d98cb42473e8842d6f29854cb1b2b4249bcfbd Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 12 Dec 2016 12:54:15 +0000 Subject: [PATCH 13/20] net: phy: Marvell: Use phy_interface_is_rgmii helper function Signed-off-by: Phil Edworthy Reviewed-by: Stefan Roese Acked-by: Joe Hershberger --- drivers/net/phy/marvell.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e76a14b47a..11aea9a348 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -177,10 +177,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) || From 3b5f52801d5de89e39b95ac155cbcda44d164240 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 12 Dec 2016 15:27:12 +0000 Subject: [PATCH 14/20] net: phy: vitesse: Fix cis8204 RGMII_ID code Commit 79e86ccb3786c8b20004db3fa10a70049456f580 "vitesse: remove duplicated argument to ||" correctly removed a redundant check. However, I believe that the original code was simply wrong, and should have been checking against RGMII_ID. To fix this and avoid similar problems in the future, use the phy_interface_is_rgmii helper function. Signed-off-by: Phil Edworthy Acked-by: Joe Hershberger --- drivers/net/phy/vitesse.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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); From 64631700645a90d5734e221e27717cc2227125b0 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 24 Jan 2017 11:15:40 -0600 Subject: [PATCH 15/20] net: phy: dp83867: Add support for MAC impedance configuration Add support for programmable MAC impedance configuration and fix typo in DT impedance parameters names. Signed-off-by: Mugunthan V N Signed-off-by: Grygorii Strashko Tested-by: Lokesh Vutla Acked-by: Joe Hershberger --- arch/arm/dts/dra72-evm-revc.dts | 4 ++-- drivers/net/phy/ti.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) 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/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 5e2b2dd9dd..2fd566cfa6 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, "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; } @@ -268,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); From 655217d968807a17df40fee3795e95bee92e5559 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 27 Jan 2017 21:25:59 +0100 Subject: [PATCH 16/20] net: designware: Fix for use with current Linux device tree for Meson GX In Uboot for Meson GX the compatible string in meson-gxbb.dtsi so far is: compatible = "amlogic,meson6-dwmac", "snps,dwmac"; On Linux in the same dt file it's compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac"; To avoid breaking ethernet with the next DT synch from Linux to U-Boot (planned as prerequisite for adding Meson GX MMC driver to U-Boot) add "amlogic,meson-gx-dwmac" to the compatibility list in the designware driver. Signed-off-by: Heiner Kallweit Acked-by: Joe Hershberger --- drivers/net/designware.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index e207bc63b8..a8e2a92def 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -763,6 +763,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" }, { } }; From 5ad9204fa9b2eb592f8c9868b23904638987bbd0 Mon Sep 17 00:00:00 2001 From: Daniel Strnad Date: Thu, 2 Feb 2017 12:11:40 +0100 Subject: [PATCH 17/20] net: fec_mxc: Fix corruption of device tree blob Modifying content of dev->name leads to the device tree corruption because it points to the node name located there. Signed-off-by: Daniel Strnad Cc: Stefano Babic Cc: Jagan Teki Acked-by: Joe Hershberger --- drivers/net/fec_mxc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 3304fddc69..9e9b8beb92 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; From 93cc2959cf93dd561409222d50e566f4e190d70d Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 9 Dec 2016 11:54:39 -0600 Subject: [PATCH 18/20] net: phy: Improve the Marvell 151x constants Use some constants for the phy configuration instead of so many magic numbers. Signed-off-by: Joe Hershberger --- drivers/net/phy/marvell.c | 47 ++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 11aea9a348..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) { @@ -286,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); @@ -295,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); } @@ -321,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); } From af2cbfd6b982f7a52414ea50b2ece0290d4b748f Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 6 Feb 2017 19:17:34 -0800 Subject: [PATCH 19/20] drivers: net: Provide Kconfig menu for PHYLIB Provide the necessary Kconfig symbols so that PHYLIB support may be enabled in Kconfig, as opposed to needing to #define these symbols in C source headers. BITBANGMII and MV88E6352_SWITCH are left out of the PHYLIB submenu as they don't seem to explicitly depend on it (i.e. they do not use the phy_driver class). Signed-off-by: Alexandru Gagniuc Acked-by: Joe Hershberger --- drivers/net/Kconfig | 28 +------------ drivers/net/phy/Kconfig | 90 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 drivers/net/phy/Kconfig diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1d31e238b6..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 diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig new file mode 100644 index 0000000000..52529f233e --- /dev/null +++ b/drivers/net/phy/Kconfig @@ -0,0 +1,90 @@ + +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_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 From a5fd13ad1913d9c66c47666dbedac7703a48e502 Mon Sep 17 00:00:00 2001 From: John Haechten Date: Fri, 9 Dec 2016 22:15:17 +0000 Subject: [PATCH 20/20] net: phy: MSCC Add Support for VSC8530-VSC8531-VSC8540-VSC8541 Signed-off-by: John Haechten Acked-by: Joe Hershberger --- configs/am335x_evm_defconfig | 1 + drivers/net/phy/Kconfig | 3 + drivers/net/phy/Makefile | 1 + drivers/net/phy/mscc.c | 508 +++++++++++++++++++++++++++++++++++ drivers/net/phy/phy.c | 3 + include/phy.h | 1 + 6 files changed, 517 insertions(+) create mode 100644 drivers/net/phy/mscc.c 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/phy/Kconfig b/drivers/net/phy/Kconfig index 52529f233e..1d514e92d3 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -45,6 +45,9 @@ config PHY_MARVELL 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" 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/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/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);