From fb8977c5be93f8e967df224fe0a44721d60e34dc Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 13 Sep 2019 19:21:16 -0500 Subject: [PATCH 01/60] net: Always build the string_to_enetaddr() helper Part of the env cleanup moved this out of the environment code and into the net code. However, this helper is sometimes needed even when the net stack isn't included. Move the helper to lib/net_utils.c like it's similarly-purposed string_to_ip(). Also rename the moved function to similar naming. Signed-off-by: Joe Hershberger Reported-by: Ondrej Jirman --- arch/arm/mach-tegra/cboot.c | 2 +- board/renesas/sh7752evb/sh7752evb.c | 2 +- board/renesas/sh7753evb/sh7753evb.c | 2 +- board/renesas/sh7757lcr/sh7757lcr.c | 4 ++-- cmd/ethsw.c | 2 +- cmd/nvedit.c | 2 +- doc/README.enetaddr | 4 ++-- include/net.h | 27 +++++++++++++-------------- lib/net_utils.c | 15 +++++++++++++++ net/eth-uclass.c | 2 +- net/eth_legacy.c | 2 +- net/net.c | 12 ------------ 12 files changed, 39 insertions(+), 37 deletions(-) diff --git a/arch/arm/mach-tegra/cboot.c b/arch/arm/mach-tegra/cboot.c index 0433081c6c..0762144ecf 100644 --- a/arch/arm/mach-tegra/cboot.c +++ b/arch/arm/mach-tegra/cboot.c @@ -495,7 +495,7 @@ static int cboot_get_ethaddr_legacy(const void *fdt, uint8_t mac[ETH_ALEN]) return -ENOENT; } - eth_parse_enetaddr(prop, mac); + string_to_enetaddr(prop, mac); if (!is_valid_ethaddr(mac)) { printf("Invalid MAC address: %s\n", prop); diff --git a/board/renesas/sh7752evb/sh7752evb.c b/board/renesas/sh7752evb/sh7752evb.c index d675f65c12..203eecf3d6 100644 --- a/board/renesas/sh7752evb/sh7752evb.c +++ b/board/renesas/sh7752evb/sh7752evb.c @@ -94,7 +94,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/board/renesas/sh7753evb/sh7753evb.c b/board/renesas/sh7753evb/sh7753evb.c index 43e13829f3..0b118b2f65 100644 --- a/board/renesas/sh7753evb/sh7753evb.c +++ b/board/renesas/sh7753evb/sh7753evb.c @@ -101,7 +101,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/board/renesas/sh7757lcr/sh7757lcr.c b/board/renesas/sh7757lcr/sh7757lcr.c index 1d7ed9977e..e8d1fdd03f 100644 --- a/board/renesas/sh7757lcr/sh7757lcr.c +++ b/board/renesas/sh7757lcr/sh7757lcr.c @@ -141,7 +141,7 @@ static void set_mac_to_sh_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = ETHER0_MAC_BASE; @@ -160,7 +160,7 @@ static void set_mac_to_sh_giga_eth_register(int channel, char *mac_string) unsigned char mac[6]; unsigned long val; - eth_parse_enetaddr(mac_string, mac); + string_to_enetaddr(mac_string, mac); if (!channel) ether = GETHER0_MAC_BASE; diff --git a/cmd/ethsw.c b/cmd/ethsw.c index 8846805799..8d271ce1f3 100644 --- a/cmd/ethsw.c +++ b/cmd/ethsw.c @@ -864,7 +864,7 @@ static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc, return 0; } - eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr); + string_to_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr); if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) { memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr)); diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 3420e0b985..81d94cd193 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -361,7 +361,7 @@ ulong env_get_hex(const char *varname, ulong default_val) int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr) { - eth_parse_enetaddr(env_get(name), enetaddr); + string_to_enetaddr(env_get(name), enetaddr); return is_valid_ethaddr(enetaddr); } diff --git a/doc/README.enetaddr b/doc/README.enetaddr index f926485986..5baa9f2179 100644 --- a/doc/README.enetaddr +++ b/doc/README.enetaddr @@ -76,12 +76,12 @@ To assist in the management of these layers, a few helper functions exist. You should use these rather than attempt to do any kind of parsing/manipulation yourself as many common errors have arisen in the past. - * void eth_parse_enetaddr(const char *addr, uchar *enetaddr); + * void string_to_enetaddr(const char *addr, uchar *enetaddr); Convert a string representation of a MAC address to the binary version. char *addr = "00:11:22:33:44:55"; uchar enetaddr[6]; -eth_parse_enetaddr(addr, enetaddr); +string_to_enetaddr(addr, enetaddr); /* enetaddr now equals { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } */ * int eth_env_get_enetaddr(char *name, uchar *enetaddr); diff --git a/include/net.h b/include/net.h index 11eca1bc6c..22c83bc213 100644 --- a/include/net.h +++ b/include/net.h @@ -826,6 +826,19 @@ static inline void net_random_ethaddr(uchar *addr) addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ } +/** + * string_to_enetaddr() - Parse a MAC address + * + * Convert a string MAC address + * + * Implemented in lib/net_utils.c (built unconditionally) + * + * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit + * hex value + * @enetaddr: Place to put MAC address (6 bytes) + */ +void string_to_enetaddr(const char *addr, uint8_t *enetaddr); + /* Convert an IP address to a string */ void ip_to_string(struct in_addr x, char *s); @@ -880,19 +893,6 @@ unsigned int random_port(void); */ int update_tftp(ulong addr, char *interface, char *devstring); -/**********************************************************************/ - -/** - * eth_parse_enetaddr() - Parse a MAC address - * - * Convert a string MAC address - * - * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit - * hex value - * @enetaddr: Place to put MAC address (6 bytes) - */ -void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr); - /** * env_get_ip() - Convert an environment value to to an ip address * @@ -905,5 +905,4 @@ static inline struct in_addr env_get_ip(char *var) { return string_to_ip(env_get(var)); } - #endif /* __NET_H__ */ diff --git a/lib/net_utils.c b/lib/net_utils.c index 9fb9d4a4b0..ed5044c3de 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -41,3 +41,18 @@ struct in_addr string_to_ip(const char *s) addr.s_addr = htonl(addr.s_addr); return addr; } + +void string_to_enetaddr(const char *addr, uint8_t *enetaddr) +{ + char *end; + int i; + + if (!enetaddr) + return; + + for (i = 0; i < 6; ++i) { + enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0; + if (addr) + addr = (*end) ? end + 1 : end; + } +} diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 3bd98b01ad..9fe4096120 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -227,7 +227,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, switch (op) { case env_op_create: case env_op_overwrite: - eth_parse_enetaddr(value, pdata->enetaddr); + string_to_enetaddr(value, pdata->enetaddr); eth_write_hwaddr(dev); break; case env_op_delete: diff --git a/net/eth_legacy.c b/net/eth_legacy.c index 41f5263526..5d6b0d7d7f 100644 --- a/net/eth_legacy.c +++ b/net/eth_legacy.c @@ -117,7 +117,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op, switch (op) { case env_op_create: case env_op_overwrite: - eth_parse_enetaddr(value, dev->enetaddr); + string_to_enetaddr(value, dev->enetaddr); eth_write_hwaddr(dev, "eth", dev->index); break; case env_op_delete: diff --git a/net/net.c b/net/net.c index 0513444eb7..284ae1bd6b 100644 --- a/net/net.c +++ b/net/net.c @@ -1625,15 +1625,3 @@ ushort env_get_vlan(char *var) { return string_to_vlan(env_get(var)); } - -void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr) -{ - char *end; - int i; - - for (i = 0; i < 6; ++i) { - enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0; - if (addr) - addr = (*end) ? end + 1 : end; - } -} From d724321f99bbaf024a5ec4bacf1520de3bc1ac87 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Fri, 13 Sep 2019 19:29:41 -0500 Subject: [PATCH 02/60] net: Improve documentation for string_to_ip() Signed-off-by: Joe Hershberger --- include/net.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/net.h b/include/net.h index 22c83bc213..834f244982 100644 --- a/include/net.h +++ b/include/net.h @@ -845,9 +845,10 @@ void ip_to_string(struct in_addr x, char *s); /** * string_to_ip() - Convert a string to ip address * - * @s: String to conver, in the format format a.b.c.d, where each value is a - * decimal number from 0 to 255 - * @return IP address, or 0 if invalid + * Implemented in lib/net_utils.c (built unconditionally) + * + * @s: Input string to parse + * @return: in_addr struct containing the parsed IP address */ struct in_addr string_to_ip(const char *s); From 6f8215681a0af8eb58ce4a112834b2ddcd547912 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 24 Sep 2019 11:41:23 -0500 Subject: [PATCH 03/60] lib: Always build support for formatting MAC and IP address Even if not communicating over the network in U-Boot, code may be manipulating and storing IP or MAC addresses to pass to Linux, etc. Signed-off-by: Joe Hershberger --- lib/vsprintf.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index c6467ecd5f..b4edee29b0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -320,7 +320,6 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width, #endif #endif -#ifdef CONFIG_CMD_NET static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, int precision, int flags) { @@ -382,7 +381,6 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); } -#endif #ifdef CONFIG_LIB_UUID /* @@ -474,7 +472,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, break; } break; -#ifdef CONFIG_CMD_NET case 'm': flags |= SPECIAL; /* Fallthrough */ @@ -493,7 +490,6 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, precision, flags); flags &= ~SPECIAL; break; -#endif #ifdef CONFIG_LIB_UUID case 'U': return uuid_string(buf, end, ptr, field_width, precision, From a6ab4b5470afadbc0f2a3d70437e3ccb88d8fa5c Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 5 Dec 2019 19:35:07 -0500 Subject: [PATCH 04/60] net: nfs: Only link in NFS code outside of SPL builds While we have networking use cases within SPL we do not support loading files via NFS at this point in time. Disable calling nfs_start() so that the NFS related code can be garbage collected at link time. Signed-off-by: Tom Rini Acked-by: Joe Hershberger --- net/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/net.c b/net/net.c index 284ae1bd6b..5114364edd 100644 --- a/net/net.c +++ b/net/net.c @@ -308,7 +308,7 @@ U_BOOT_ENV_CALLBACK(dnsip, on_dnsip); */ void net_auto_load(void) { -#if defined(CONFIG_CMD_NFS) +#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD) const char *s = env_get("autoload"); if (s != NULL && strcmp(s, "NFS") == 0) { @@ -496,7 +496,7 @@ restart: ping_start(); break; #endif -#if defined(CONFIG_CMD_NFS) +#if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD) case NFS: nfs_start(); break; From 1f60789602e0d5f5f9a8b507f25737c65b5d8daa Mon Sep 17 00:00:00 2001 From: Priyanka Jain Date: Tue, 5 Nov 2019 04:05:11 +0000 Subject: [PATCH 05/60] net/phy: Fix phy_connect() for phy addr 0 Fix 'mask' calculation in phy_connect() for phy addr '0'. 'mask' is getting set to '0xffffffff' for phy addr '0' in phy_connect() whereas expected value is '0'. Signed-off-by: Priyanka Jain Reported-by: tetsu-aoki via github Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f2d17aa91a..6be0709e34 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -997,7 +997,7 @@ struct phy_device *phy_connect(struct mii_dev *bus, int addr, #endif { struct phy_device *phydev = NULL; - uint mask = (addr > 0) ? (1 << addr) : 0xffffffff; + uint mask = (addr >= 0) ? (1 << addr) : 0xffffffff; #ifdef CONFIG_PHY_FIXED phydev = phy_connect_fixed(bus, dev, interface); From 8524423da9afc637167057dd69e1f52f6dbcc8e5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 5 Nov 2019 12:48:19 +0100 Subject: [PATCH 06/60] net: avoid address-of-packed-member error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sandbox_defconfig does not compile using GCC 9.2.1: net/net.c: In function ‘net_process_received_packet’: net/net.c:1288:23: error: taking address of packed member of ‘struct ip_udp_hdr’ may result in an unaligned pointer value [-Werror=address-of-packed-member] 1288 | sumptr = (ushort *)&(ip->udp_src); | ^~~~~~~~~~~~~~ Avoid the error by using a u8 pointer instead of an u16 pointer and in-lining ntohs(). Simplify the checksumming of the last message byte. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Goldschmidt Acked-by: Joe Hershberger --- net/net.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/net/net.c b/net/net.c index 5114364edd..5199d679a1 100644 --- a/net/net.c +++ b/net/net.c @@ -1271,7 +1271,7 @@ void net_process_received_packet(uchar *in_packet, int len) #ifdef CONFIG_UDP_CHECKSUM if (ip->udp_xsum != 0) { ulong xsum; - ushort *sumptr; + u8 *sumptr; ushort sumlen; xsum = ip->ip_p; @@ -1282,22 +1282,16 @@ void net_process_received_packet(uchar *in_packet, int len) xsum += (ntohl(ip->ip_dst.s_addr) >> 0) & 0x0000ffff; sumlen = ntohs(ip->udp_len); - sumptr = (ushort *)&(ip->udp_src); + sumptr = (u8 *)&ip->udp_src; while (sumlen > 1) { - ushort sumdata; - - sumdata = *sumptr++; - xsum += ntohs(sumdata); + /* inlined ntohs() to avoid alignment errors */ + xsum += (sumptr[0] << 8) + sumptr[1]; + sumptr += 2; sumlen -= 2; } - if (sumlen > 0) { - ushort sumdata; - - sumdata = *(unsigned char *)sumptr; - sumdata = (sumdata << 8) & 0xff00; - xsum += sumdata; - } + if (sumlen > 0) + xsum += (sumptr[0] << 8) + sumptr[0]; while ((xsum >> 16) != 0) { xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff); From ca48cb40283e2346603491a6214e95117c275f2f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Fri, 15 Nov 2019 22:20:13 -0800 Subject: [PATCH 07/60] net: tftp: Fix tftp store address check in store_block() During testing of qemu-riscv32 with a 2GiB memory configuration, tftp always fails with a error message: Load address: 0x84000000 Loading: # TFTP error: trying to overwrite reserved memory... It turns out the result of 'tftp_load_addr + tftp_load_size' just overflows (0x100000000) and the test logic in store_block() fails. Fix this by adjusting the end address to ULONG_MAX when overflow is detected. Fixes: a156c47e39ad ("tftp: prevent overwriting reserved memory") Signed-off-by: Bin Meng Acked-by: Joe Hershberger --- net/tftp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/tftp.c b/net/tftp.c index 5a69bca641..1e3c18ae69 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -171,8 +171,13 @@ static inline int store_block(int block, uchar *src, unsigned int len) void *ptr; #ifdef CONFIG_LMB + ulong end_addr = tftp_load_addr + tftp_load_size; + + if (!end_addr) + end_addr = ULONG_MAX; + if (store_addr < tftp_load_addr || - store_addr + len > tftp_load_addr + tftp_load_size) { + store_addr + len > end_addr) { puts("\nTFTP error: "); puts("trying to overwrite reserved memory...\n"); return -1; From 5ee989c5aa0c26c59fb7c60cb6d0d6cd33699996 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:40 +0200 Subject: [PATCH 08/60] net: phy: ti: rename ti.c to dp83867.c The driver ti.c is actually driver for TI DP83867x PHYs, so rename it accordingly. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/Makefile | 2 +- drivers/net/phy/{ti.c => dp83867.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/net/phy/{ti.c => dp83867.c} (100%) diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 76b6197009..78955c57a8 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o obj-$(CONFIG_PHY_REALTEK) += realtek.o obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o -obj-$(CONFIG_PHY_TI) += ti.o +obj-$(CONFIG_PHY_TI) += dp83867.o obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o obj-$(CONFIG_PHY_VITESSE) += vitesse.o diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/dp83867.c similarity index 100% rename from drivers/net/phy/ti.c rename to drivers/net/phy/dp83867.c From ee622f03ccb8108482c58b15e0126f5b97a2b062 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:41 +0200 Subject: [PATCH 09/60] net: phy: dp83867: move static initialization to .probe() Move static, one-time initialization to .probe() callback. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/dp83867.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 7509936465..8dc2163342 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -204,18 +204,11 @@ static int dp83867_config(struct phy_device *phydev) unsigned int val, delay, cfg2; int ret, bs; - if (!phydev->priv) { - dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); - if (!dp83867) - return -ENOMEM; + dp83867 = (struct dp83867_private *)phydev->priv; - phydev->priv = dp83867; - ret = dp83867_of_init(phydev); - if (ret) - goto err_out; - } else { - dp83867 = (struct dp83867_private *)phydev->priv; - } + ret = dp83867_of_init(phydev); + if (ret) + return ret; /* Restart the PHY. */ val = phy_read(phydev, MDIO_DEVAD_NONE, DP83867_CTRL); @@ -324,15 +317,27 @@ static int dp83867_config(struct phy_device *phydev) return 0; err_out: - kfree(dp83867); return ret; } +static int dp83867_probe(struct phy_device *phydev) +{ + struct dp83867_private *dp83867; + + dp83867 = kzalloc(sizeof(*dp83867), GFP_KERNEL); + if (!dp83867) + return -ENOMEM; + + phydev->priv = dp83867; + return 0; +} + static struct phy_driver DP83867_driver = { .name = "TI DP83867", .uid = 0x2000a231, .mask = 0xfffffff0, .features = PHY_GBIT_FEATURES, + .probe = dp83867_probe, .config = &dp83867_config, .startup = &genphy_startup, .shutdown = &genphy_shutdown, From fb6038390ebe8717a66dd3a4e37bffb96e50c07a Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:42 +0200 Subject: [PATCH 10/60] dt-bindings: phy: dp83867: Add documentation for disabling clock output Based on commit 980066e6d964 ("dt-bindings: phy: dp83867: Add documentation for disabling clock output") of mainline linux kernel. The clock output is generally only used for testing and development and not used to daisy-chain PHYs. It's just a source of RF noise afterward. Add a mux value for "off". I've added it as another enumeration to the output property. In the actual PHY, the mux and the output enable are independently controllable. However, it doesn't seem useful to be able to describe the mux setting when the output is disabled. Document that PHY's default setting will be left as is if the property is omitted. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/ti,dp83867.txt | 6 ++++-- include/dt-bindings/net/ti-dp83867.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/device-tree-bindings/net/ti,dp83867.txt b/doc/device-tree-bindings/net/ti,dp83867.txt index 034146f5f8..268220964a 100644 --- a/doc/device-tree-bindings/net/ti,dp83867.txt +++ b/doc/device-tree-bindings/net/ti,dp83867.txt @@ -12,8 +12,10 @@ Required properties: compensate for the board being designed with the lanes swapped. - enet-phy-no-lane-swap - Indicates that PHY will disable swap of the TX/RX lanes. - - ti,clk-output-sel - Clock output select - see dt-bindings/net/ti-dp83867.h - for applicable values + - ti,clk-output-sel - Muxing option for CLK_OUT pin. See dt-bindings/net/ti-dp83867.h + for applicable values. The CLK_OUT pin can also + be disabled by this property. When omitted, the + PHY's default will be left as is. Default child nodes are standard Ethernet PHY device nodes as described in doc/devicetree/bindings/net/ethernet.txt diff --git a/include/dt-bindings/net/ti-dp83867.h b/include/dt-bindings/net/ti-dp83867.h index 85d08f6974..cde5aa7e27 100644 --- a/include/dt-bindings/net/ti-dp83867.h +++ b/include/dt-bindings/net/ti-dp83867.h @@ -45,5 +45,6 @@ #define DP83867_CLK_O_SEL_CHN_C_TCLK 0xA #define DP83867_CLK_O_SEL_CHN_D_TCLK 0xB #define DP83867_CLK_O_SEL_REF_CLK 0xC - +/* Special flag to indicate clock should be off */ +#define DP83867_CLK_O_SEL_OFF 0xFFFFFFFF #endif From b3b9b128d5432f7b17ed4afeffa1dad04eefec0a Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:43 +0200 Subject: [PATCH 11/60] net: phy: dp83867: Add ability to disable output clock Based on commit 13c83cf8af0d ("net: phy: dp83867: Add ability to disable output clock") of mainline linux kernel. Generally, the output clock pin is only used for testing and only serves as a source of RF noise after this. It could be used to daisy-chain PHYs, but this is uncommon. Since the PHY can disable the output, make doing so an option. I do this by adding another enumeration to the allowed values of ti,clk-output-sel. The code was not using the value DP83867_CLK_O_SEL_REF_CLK as one might expect: to select the REF_CLK as the output. Rather it meant "keep clock output setting as is", which, depending on PHY strapping, might not be outputting REF_CLK. Change this so DP83867_CLK_O_SEL_REF_CLK means enable REF_CLK output. Omitting the property will leave the setting as is (which was the previous behavior in this case). Out of range values were silently converted into DP83867_CLK_O_SEL_REF_CLK. Change this so they generate an error. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/dp83867.c | 53 ++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 8dc2163342..cd3c1c596a 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -83,6 +83,7 @@ #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 #define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83867_IO_MUX_CFG_CLK_O_DISABLE BIT(6) #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK \ GENMASK(0x1f, DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT) @@ -103,6 +104,7 @@ struct dp83867_private { int io_impedance; bool rxctrl_strap_quirk; int port_mirroring; + bool set_clk_output; unsigned int clk_output_sel; }; @@ -134,16 +136,28 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; ofnode node; - u16 val; + int ret; node = phy_get_ofnode(phydev); if (!ofnode_valid(node)) return -EINVAL; - /* Keep the default value if ti,clk-output-sel is not set */ - dp83867->clk_output_sel = - ofnode_read_u32_default(node, "ti,clk-output-sel", - DP83867_CLK_O_SEL_REF_CLK); + /* Optional configuration */ + ret = ofnode_read_u32(node, "ti,clk-output-sel", + &dp83867->clk_output_sel); + /* If not set, keep default */ + if (!ret) { + dp83867->set_clk_output = true; + /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or + * DP83867_CLK_O_SEL_OFF. + */ + if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK && + dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) { + pr_debug("ti,clk-output-sel value %u out of range\n", + dp83867->clk_output_sel); + return -EINVAL; + } + } if (ofnode_read_bool(node, "ti,max-output-impedance")) dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; @@ -170,18 +184,6 @@ static int dp83867_of_init(struct phy_device *phydev) if (ofnode_read_bool(node, "enet-phy-lane-no-swap")) dp83867->port_mirroring = DP83867_PORT_MIRRORING_DIS; - - /* Clock output selection if muxing property is set */ - if (dp83867->clk_output_sel != DP83867_CLK_O_SEL_REF_CLK) { - val = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG); - val &= ~DP83867_IO_MUX_CFG_CLK_O_SEL_MASK; - val |= (dp83867->clk_output_sel << - DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT); - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG, val); - } - return 0; } #else @@ -313,6 +315,23 @@ static int dp83867_config(struct phy_device *phydev) if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) dp83867_config_port_mirroring(phydev); + /* Clock output selection if muxing property is set */ + if (dp83867->set_clk_output) { + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG); + + if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) { + val |= DP83867_IO_MUX_CFG_CLK_O_DISABLE; + } else { + val &= ~(DP83867_IO_MUX_CFG_CLK_O_SEL_MASK | + DP83867_IO_MUX_CFG_CLK_O_DISABLE); + val |= dp83867->clk_output_sel << + DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT; + } + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG, val); + } + genphy_config_aneg(phydev); return 0; From 20f7ea4c35ff98003c29eec442700af04496b49f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:44 +0200 Subject: [PATCH 12/60] net: phy: dp83867: rework delay rgmii delay handling Based on commit c11669a2757e ("net: phy: dp83867: Rework delay rgmii delay handling") of mainline linux kernel. The current code is assuming the reset default of the delay control register was to have delay disabled. This is what the datasheet shows as the register's initial value. However, that's not actually true: the default is controlled by the PHY's pin strapping. This patch: - insures the other direction's delay is disabled If the interface mode is selected as RX or TX delay only - validates the delay values and fail if they are not in range - checks if the board is strapped to have a delay and is configured to use "rgmii" mode and warning is generated that "rgmii-id" should have been used. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/dp83867.c | 76 ++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index cd3c1c596a..1721f6892b 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -25,6 +25,7 @@ #define DP83867_CFG4 0x0031 #define DP83867_RGMIICTL 0x0032 #define DP83867_STRAP_STS1 0x006E +#define DP83867_STRAP_STS2 0x006f #define DP83867_RGMIIDCTL 0x0086 #define DP83867_IO_MUX_CFG 0x0170 @@ -52,6 +53,13 @@ /* STRAP_STS1 bits */ #define DP83867_STRAP_STS1_RESERVED BIT(11) +/* STRAP_STS2 bits */ +#define DP83867_STRAP_STS2_CLK_SKEW_TX_MASK GENMASK(6, 4) +#define DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT 4 +#define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK GENMASK(2, 0) +#define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT 0 +#define DP83867_STRAP_STS2_CLK_SKEW_NONE BIT(2) + /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 #define DP83867_PHYCR_RESERVED_MASK BIT(11) @@ -63,7 +71,9 @@ #define DP83867_PHYCTRL_TXFIFO_SHIFT 14 /* RGMIIDCTL bits */ +#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf #define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 +#define DP83867_RGMII_RX_CLK_DELAY_MAX 0xf /* CFG2 bits */ #define MII_DP83867_CFG2_SPEEDOPT_10EN 0x0040 @@ -74,8 +84,6 @@ #define MII_DP83867_CFG2_MASK 0x003F /* User setting - can be taken from DTS */ -#define DEFAULT_RX_ID_DELAY DP83867_RGMIIDCTL_2_25_NS -#define DEFAULT_TX_ID_DELAY DP83867_RGMIIDCTL_2_75_NS #define DEFAULT_FIFO_DEPTH DP83867_PHYCR_FIFO_DEPTH_4_B_NIB /* IO_MUX_CFG bits */ @@ -98,8 +106,8 @@ enum { }; struct dp83867_private { - int rx_id_delay; - int tx_id_delay; + u32 rx_id_delay; + u32 tx_id_delay; int fifo_depth; int io_impedance; bool rxctrl_strap_quirk; @@ -168,13 +176,55 @@ static int dp83867_of_init(struct phy_device *phydev) if (ofnode_read_bool(node, "ti,dp83867-rxctrl-strap-quirk")) dp83867->rxctrl_strap_quirk = true; - dp83867->rx_id_delay = ofnode_read_u32_default(node, - "ti,rx-internal-delay", - DEFAULT_RX_ID_DELAY); - dp83867->tx_id_delay = ofnode_read_u32_default(node, - "ti,tx-internal-delay", - DEFAULT_TX_ID_DELAY); + /* Existing behavior was to use default pin strapping delay in rgmii + * mode, but rgmii should have meant no delay. Warn existing users. + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_STRAP_STS2); + u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >> + DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT; + u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >> + DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT; + + if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE || + rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE) + pr_warn("PHY has delays via pin strapping, but phy-mode = 'rgmii'\n" + "Should be 'rgmii-id' to use internal delays\n"); + } + + /* RX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + ret = ofnode_read_u32(node, "ti,rx-internal-delay", + &dp83867->rx_id_delay); + if (ret) { + pr_debug("ti,rx-internal-delay must be specified\n"); + return ret; + } + if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { + pr_debug("ti,rx-internal-delay value of %u out of range\n", + dp83867->rx_id_delay); + return -EINVAL; + } + } + + /* TX delay *must* be specified if internal delay of RX is used. */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + ret = ofnode_read_u32(node, "ti,tx-internal-delay", + &dp83867->tx_id_delay); + if (ret) { + debug("ti,tx-internal-delay must be specified\n"); + return ret; + } + if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { + pr_debug("ti,tx-internal-delay value of %u out of range\n", + dp83867->tx_id_delay); + return -EINVAL; + } + } dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth", DEFAULT_FIFO_DEPTH); @@ -191,8 +241,8 @@ static int dp83867_of_init(struct phy_device *phydev) { struct dp83867_private *dp83867 = phydev->priv; - dp83867->rx_id_delay = DEFAULT_RX_ID_DELAY; - dp83867->tx_id_delay = DEFAULT_TX_ID_DELAY; + dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_25_NS; + dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_75_NS; dp83867->fifo_depth = DEFAULT_FIFO_DEPTH; dp83867->io_impedance = -EINVAL; @@ -281,6 +331,8 @@ static int dp83867_config(struct phy_device *phydev) val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL); + val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN); From 253a5ff8712c4dc5821ebdc4e4124901d37c0339 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:45 +0200 Subject: [PATCH 13/60] net: phy: dp83867: io impedance is not dependent on RGMII delay Based on commit 27708eb5481b ("net: phy: dp83867: IO impedance is not dependent on RGMII delay") of mainline linux kernel. The driver would only set the IO impedance value when RGMII internal delays were enabled. There is no reason for this. Move the IO impedance block out of the RGMII delay block. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/dp83867.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 1721f6892b..f9bb925646 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -351,17 +351,17 @@ static int dp83867_config(struct phy_device *phydev) phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL, delay); + } - if (dp83867->io_impedance >= 0) { - val = phy_read_mmd(phydev, - DP83867_DEVADDR, - DP83867_IO_MUX_CFG); - val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; - val |= dp83867->io_impedance & - DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_IO_MUX_CFG, val); - } + if (dp83867->io_impedance >= 0) { + val = phy_read_mmd(phydev, + DP83867_DEVADDR, + DP83867_IO_MUX_CFG); + val &= ~DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + val |= dp83867->io_impedance & + DP83867_IO_MUX_CFG_IO_IMPEDANCE_CTRL; + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_IO_MUX_CFG, val); } if (dp83867->port_mirroring != DP83867_PORT_MIRRORING_KEEP) From 37d6265f2bfa216e97324837471cb78cafe7b57f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:46 +0200 Subject: [PATCH 14/60] net: phy: dp83867: refactor rgmii configuration Refactor SGMII configuration to group all settings together and reduce number of MDIO transactions. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- drivers/net/phy/dp83867.c | 75 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index f9bb925646..a43793cd42 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -62,9 +62,9 @@ /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 14) #define DP83867_PHYCR_RESERVED_MASK BIT(11) #define DP83867_MDI_CROSSOVER 5 -#define DP83867_MDI_CROSSOVER_AUTO 2 #define DP83867_MDI_CROSSOVER_MDIX 2 #define DP83867_PHYCTRL_SGMIIEN 0x0800 #define DP83867_PHYCTRL_RXFIFO_SHIFT 12 @@ -277,11 +277,11 @@ static int dp83867_config(struct phy_device *phydev) } if (phy_interface_is_rgmii(phydev)) { - ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, - (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) | - (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); - if (ret) + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); + if (val < 0) goto err_out; + val &= ~DP83867_PHYCR_FIFO_DEPTH_MASK; + val |= (dp83867->fifo_depth << DP83867_PHYCR_FIFO_DEPTH_SHIFT); /* The code below checks if "port mirroring" N/A MODE4 has been * enabled during power on bootstrap. @@ -293,16 +293,39 @@ static int dp83867_config(struct phy_device *phydev) * register's bit 11 (marked as RESERVED). */ - bs = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_STRAP_STS1); - val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL); - if (bs & DP83867_STRAP_STS1_RESERVED) { + bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1); + if (bs & DP83867_STRAP_STS1_RESERVED) val &= ~DP83867_PHYCR_RESERVED_MASK; - phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, - val); - } - } else if (phy_interface_is_sgmii(phydev)) { + ret = phy_write(phydev, MDIO_DEVAD_NONE, + MII_DP83867_PHYCTRL, val); + + val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIICTL); + + val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + val |= (DP83867_RGMII_TX_CLK_DELAY_EN | + DP83867_RGMII_RX_CLK_DELAY_EN); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + val |= DP83867_RGMII_TX_CLK_DELAY_EN; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + val |= DP83867_RGMII_RX_CLK_DELAY_EN; + + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val); + + delay = (dp83867->rx_id_delay | + (dp83867->tx_id_delay << + DP83867_RGMII_TX_CLK_DELAY_SHIFT)); + + phy_write_mmd(phydev, DP83867_DEVADDR, + DP83867_RGMIIDCTL, delay); + } + + if (phy_interface_is_sgmii(phydev)) { phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, (BMCR_ANENABLE | BMCR_FULLDPLX | BMCR_SPEED1000)); @@ -327,32 +350,6 @@ static int dp83867_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_BISCR, 0x0); } - if (phy_interface_is_rgmii(phydev)) { - val = phy_read_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIICTL); - - val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | - DP83867_RGMII_RX_CLK_DELAY_EN); - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - val |= (DP83867_RGMII_TX_CLK_DELAY_EN | - DP83867_RGMII_RX_CLK_DELAY_EN); - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - val |= DP83867_RGMII_TX_CLK_DELAY_EN; - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - val |= DP83867_RGMII_RX_CLK_DELAY_EN; - - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIICTL, val); - - delay = (dp83867->rx_id_delay | - (dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT)); - - phy_write_mmd(phydev, DP83867_DEVADDR, - DP83867_RGMIIDCTL, delay); - } - if (dp83867->io_impedance >= 0) { val = phy_read_mmd(phydev, DP83867_DEVADDR, From 5efb69298be40b1f277157b41e38442ab50eb4f2 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 18 Nov 2019 23:04:47 +0200 Subject: [PATCH 15/60] arm: dts: k3-am654-base-board-u-boot: change cpsw2g interface mode to rgmii-rxid The AM654 SoC doesn't allow to disabling RGMII TX internal delay in CPSW2G MAC. Hence, change CPSW2G interface mode to "rgmii-rxid" - RGMII with internal RX delay provided by the PHY, the MAC will add an TX delay in this case. Signed-off-by: Grygorii Strashko Acked-by: Joe Hershberger --- arch/arm/dts/k3-am654-base-board-u-boot.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi index 8589f76d23..bea80c5d00 100644 --- a/arch/arm/dts/k3-am654-base-board-u-boot.dtsi +++ b/arch/arm/dts/k3-am654-base-board-u-boot.dtsi @@ -336,13 +336,12 @@ reg = <0>; /* TODO: phy reset: TCA9555RTWR(i2c:0x21)[p04].GPIO_MCU_RGMII_RSTN */ ti,rx-internal-delay = ; - ti,tx-internal-delay = ; ti,fifo-depth = ; }; }; &cpsw_port1 { - phy-mode = "rgmii-id"; + phy-mode = "rgmii-rxid"; phy-handle = <&phy0>; }; From 13b725fd24bd7d6acdd7cb7c3c4238d0b305985e Mon Sep 17 00:00:00 2001 From: Stefan Chulski Date: Thu, 15 Aug 2019 18:08:41 -0400 Subject: [PATCH 16/60] net: mvpp2x: fix traffic stuck after PHY start error Issue: - Network stuck if autonegotion fails. Issue root cause: - When autonegotiation fails during port open procedure, the packet processor configuration does not finish and open procedure exits with error. - However, this doesn't prevent u-boot network framework from calling send and receive procedures. - Using transmit and receive functions of misconfigured packet processor will cause traffic to get stuck. Fix: - Continue packet processor configuration even if autonegotiation fails. Only error message is triggered in this case. - Exit transmit and receive functions if there is no PHY link indication. - U-boot network framework now calls open procedure again during next transmit initiation. Signed-off-by: Stefan Chulski Reviewed-by: Igal Liberman Tested-by: Igal Liberman Reviewed-by: Ramon Fried Acked-by: Joe Hershberger --- drivers/net/mvpp2.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 8148c03d22..4ee765872c 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -4495,7 +4495,7 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) gop_port_enable(port, 0); } -static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) +static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) { struct phy_device *phy_dev; @@ -4505,7 +4505,7 @@ static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) port->phy_dev = phy_dev; if (!phy_dev) { netdev_err(port->dev, "cannot connect to phy\n"); - return -ENODEV; + return; } phy_dev->supported &= PHY_GBIT_FEATURES; phy_dev->advertising = phy_dev->supported; @@ -4517,18 +4517,14 @@ static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) phy_config(phy_dev); phy_startup(phy_dev); - if (!phy_dev->link) { + if (!phy_dev->link) printf("%s: No link\n", phy_dev->dev->name); - return -1; - } - - port->init = 1; + else + port->init = 1; } else { mvpp2_egress_enable(port); mvpp2_ingress_enable(port); } - - return 0; } static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) @@ -4568,10 +4564,7 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) } if (port->phy_node) { - err = mvpp2_phy_connect(dev, port); - if (err < 0) - return err; - + mvpp2_phy_connect(dev, port); mvpp2_link_event(port); } else { mvpp2_egress_enable(port); @@ -5176,6 +5169,10 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) struct mvpp2_rx_queue *rxq; u8 *data; + if (port->phy_node) + if (!port->phy_dev->link) + return 0; + /* Process RX packets */ rxq = port->rxqs[0]; @@ -5241,6 +5238,10 @@ static int mvpp2_send(struct udevice *dev, void *packet, int length) int tx_done; int timeout; + if (port->phy_node) + if (!port->phy_dev->link) + return 0; + txq = port->txqs[0]; aggr_txq = &port->priv->aggr_txqs[smp_processor_id()]; From 623948377acf1ba8f4b277e954155035b9800330 Mon Sep 17 00:00:00 2001 From: Grzegorz Jaszczyk Date: Thu, 15 Aug 2019 18:08:42 -0400 Subject: [PATCH 17/60] net: mvpp2: mark phy as invalid in case of missing appropriate driver If the phy doesn't match with any existing u-boot drivers, the phy framework will connect it to the generic one which uid == 0xffffffff. In this case, act as if the phy wouldn't be declared in dts. Otherwise, in case of 3310 (for which the driver doesn't exist) the link is marked as always down. Removing phy entry from dts in case of 3310 is not a good option because it is required for the phy_fw_down procedure. This patch fixes the issue with the link always down on MCBIN board. nhed: added NULL deref test. Signed-off-by: Grzegorz Jaszczyk Reviewed-by: Igal Liberman Tested-by: Igal Liberman Signed-off-by: Nevo Hed Reviewed-by: Ramon Fried Acked-by: Joe Hershberger --- drivers/net/mvpp2.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 4ee765872c..64b03bff92 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -4502,6 +4502,29 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) if (!port->init || port->link == 0) { phy_dev = phy_connect(port->bus, port->phyaddr, dev, port->phy_interface); + + /* + * If the phy doesn't match with any existing u-boot drivers the + * phy framework will connect it to generic one which + * uid == 0xffffffff. In this case act as if the phy wouldn't be + * declared in dts. Otherwise in case of 3310 (for which the + * driver doesn't exist) the link will not be correctly + * detected. Removing phy entry from dts in case of 3310 is not + * an option because it is required for the phy_fw_down + * procedure. + */ + if (phy_dev && + phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ + netdev_warn(port->dev, + "Marking phy as invalid, link will not be checked\n"); + /* set phy_addr to invalid value */ + port->phyaddr = PHY_MAX_ADDR; + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + + return; + } + port->phy_dev = phy_dev; if (!phy_dev) { netdev_err(port->dev, "cannot connect to phy\n"); From 06f555274e9f8a695243bdd791186adb4ffc68e0 Mon Sep 17 00:00:00 2001 From: Nevo Hed Date: Thu, 15 Aug 2019 18:08:43 -0400 Subject: [PATCH 18/60] arm: dts: armada-cp110-*dtsi: add xmdio nodes Based on upstream-linux See https://github.com/torvalds/linux/commit/f66b2aff. However made the XSMI register window 0x16 (22) bytes per my reading of the functional spec. Similar commits in Marvels own repo bump it to 0x200 (512) bytes but I did not see the reasoning for that. https://github.com/MarvellEmbeddedProcessors/u-boot-marvell/commit/4d932b4. Also added device-name attributes to prevent ambiguity in the `mdio` command. Signed-off-by: Nevo Hed Reviewed-by: Ramon Fried Acked-by: Joe Hershberger --- arch/arm/dts/armada-cp110-master.dtsi | 9 +++++++++ arch/arm/dts/armada-cp110-slave.dtsi | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi index e4c17e9f4b..cd5c974482 100644 --- a/arch/arm/dts/armada-cp110-master.dtsi +++ b/arch/arm/dts/armada-cp110-master.dtsi @@ -99,6 +99,15 @@ device-name = "cpm-mdio"; }; + cpm_xmdio: mdio@12a600 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,xmdio"; + reg = <0x12a600 0x16>; + status = "disabled"; + device-name = "cpm-xmdio"; + }; + cpm_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi index 2fbd7b5514..b426a4eb69 100644 --- a/arch/arm/dts/armada-cp110-slave.dtsi +++ b/arch/arm/dts/armada-cp110-slave.dtsi @@ -99,6 +99,15 @@ device-name = "cps-mdio"; }; + cps_xmdio: mdio@12a600 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,xmdio"; + reg = <0x12a600 0x16>; + status = "disabled"; + device-name = "cps-xmdio"; + }; + cps_syscon0: system-controller@440000 { compatible = "marvell,cp110-system-controller0", "syscon"; From 2a42870778b78c11d2f4fb1cbc515b5176aaad88 Mon Sep 17 00:00:00 2001 From: Nevo Hed Date: Thu, 15 Aug 2019 18:08:44 -0400 Subject: [PATCH 19/60] net: mvpp2: use new MVMDIO driver This commit ports mvpp2 to use the recently introduced Marvell MDIO (MVMDIO) driver. It removes direct interaction with the SMI & XSMI busses. This commit is based in part on earlier work by Ken Ma in Marvell's own downstream repo: https://github.com/MarvellEmbeddedProcessors/u-boot-marvell/commit/c81dc39. The above refrenced work was based on an MVMDIO implementation that never made it into U-Boot. With this patch the mvpp2 driver switches to use the new MVMDIO driver that is based on a more universal mdio-uclass implementation. Signed-off-by: Nevo Hed Reviewed-by: Ramon Fried Acked-by: Joe Hershberger --- drivers/net/mvpp2.c | 195 ++++---------------------------------------- 1 file changed, 18 insertions(+), 177 deletions(-) diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 64b03bff92..c5d1f9cf9f 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -33,6 +33,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -63,8 +64,6 @@ do { \ #define MTU 1500 #define RX_BUFFER_SIZE (ALIGN(MTU + WRAP, ARCH_DMA_MINALIGN)) -#define MVPP2_SMI_TIMEOUT 10000 - /* RX Fifo Registers */ #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) #define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port)) @@ -491,23 +490,8 @@ do { \ #define MVPP2_QUEUE_NEXT_DESC(q, index) \ (((index) < (q)->last_desc) ? ((index) + 1) : 0) -/* SMI: 0xc0054 -> offset 0x54 to lms_base */ -#define MVPP21_SMI 0x0054 /* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */ #define MVPP22_SMI 0x1200 -#define MVPP2_PHY_REG_MASK 0x1f -/* SMI register fields */ -#define MVPP2_SMI_DATA_OFFS 0 /* Data */ -#define MVPP2_SMI_DATA_MASK (0xffff << MVPP2_SMI_DATA_OFFS) -#define MVPP2_SMI_DEV_ADDR_OFFS 16 /* PHY device address */ -#define MVPP2_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/ -#define MVPP2_SMI_OPCODE_OFFS 26 /* Write/Read opcode */ -#define MVPP2_SMI_OPCODE_READ (1 << MVPP2_SMI_OPCODE_OFFS) -#define MVPP2_SMI_READ_VALID (1 << 27) /* Read Valid */ -#define MVPP2_SMI_BUSY (1 << 28) /* Busy */ - -#define MVPP2_PHY_ADDR_MASK 0x1f -#define MVPP2_PHY_REG_MASK 0x1f /* Additional PPv2.2 offsets */ #define MVPP22_MPCS 0x007000 @@ -953,7 +937,6 @@ struct mvpp2_port { /* Per-port registers' base address */ void __iomem *base; - void __iomem *mdio_base; struct mvpp2_rx_queue **rxqs; struct mvpp2_tx_queue **txqs; @@ -974,9 +957,8 @@ struct mvpp2_port { struct phy_device *phy_dev; phy_interface_t phy_interface; - int phy_node; int phyaddr; - struct mii_dev *bus; + struct udevice *mdio_dev; #ifdef CONFIG_DM_GPIO struct gpio_desc phy_reset_gpio; struct gpio_desc phy_tx_disable_gpio; @@ -4500,8 +4482,8 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) struct phy_device *phy_dev; if (!port->init || port->link == 0) { - phy_dev = phy_connect(port->bus, port->phyaddr, dev, - port->phy_interface); + phy_dev = dm_mdio_phy_connect(port->mdio_dev, port->phyaddr, + dev, port->phy_interface); /* * If the phy doesn't match with any existing u-boot drivers the @@ -4586,7 +4568,7 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) return err; } - if (port->phy_node) { + if (port->phyaddr < PHY_MAX_ADDR) { mvpp2_phy_connect(dev, port); mvpp2_link_event(port); } else { @@ -4725,35 +4707,25 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) u32 id; u32 phyaddr = 0; int phy_mode = -1; - - /* Default mdio_base from the same eth base */ - if (port->priv->hw_version == MVPP21) - port->mdio_base = port->priv->lms_base + MVPP21_SMI; - else - port->mdio_base = port->priv->iface_base + MVPP22_SMI; + int ret; phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); if (phy_node > 0) { - ofnode phy_ofnode; - fdt_addr_t phy_base; - + int parent; phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0); if (phyaddr < 0) { dev_err(&pdev->dev, "could not find phy address\n"); return -1; } - - phy_ofnode = ofnode_get_parent(offset_to_ofnode(phy_node)); - phy_base = ofnode_get_addr(phy_ofnode); - port->mdio_base = (void *)phy_base; - - if (port->mdio_base < 0) { - dev_err(&pdev->dev, "could not find mdio base address\n"); - return -1; - } + parent = fdt_parent_offset(gd->fdt_blob, phy_node); + ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent, + &port->mdio_dev); + if (ret) + return ret; } else { - phy_node = 0; + /* phy_addr is set to invalid value */ + phyaddr = PHY_MAX_ADDR; } phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL); @@ -4791,7 +4763,6 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) port->first_rxq = port->id * rxq_number; else port->first_rxq = port->id * port->priv->max_port_rxqs; - port->phy_node = phy_node; port->phy_interface = phy_mode; port->phyaddr = phyaddr; @@ -5068,118 +5039,6 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) return 0; } -/* SMI / MDIO functions */ - -static int smi_wait_ready(struct mvpp2_port *priv) -{ - u32 timeout = MVPP2_SMI_TIMEOUT; - u32 smi_reg; - - /* wait till the SMI is not busy */ - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Error: SMI busy timeout\n"); - return -EFAULT; - } - } while (smi_reg & MVPP2_SMI_BUSY); - - return 0; -} - -/* - * mpp2_mdio_read - miiphy_read callback function. - * - * Returns 16bit phy register value, or 0xffff on error - */ -static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mvpp2_port *priv = bus->priv; - u32 smi_reg; - u32 timeout; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy address and regiser offset and read opcode */ - smi_reg = (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS) - | MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - /* wait till read value is ready */ - timeout = MVPP2_SMI_TIMEOUT; - - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Err: SMI read ready timeout\n"); - return -EFAULT; - } - } while (!(smi_reg & MVPP2_SMI_READ_VALID)); - - /* Wait for the data to update in the SMI register */ - for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++) - ; - - return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK; -} - -/* - * mpp2_mdio_write - miiphy_write callback function. - * - * Returns 0 if write succeed, -EINVAL on bad parameters - * -ETIME on timeout - */ -static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 value) -{ - struct mvpp2_port *priv = bus->priv; - u32 smi_reg; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy addr and reg offset and write opcode and data */ - smi_reg = value << MVPP2_SMI_DATA_OFFS; - smi_reg |= (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS); - smi_reg &= ~MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - return 0; -} - static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) { struct mvpp2_port *port = dev_get_priv(dev); @@ -5192,7 +5051,7 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) struct mvpp2_rx_queue *rxq; u8 *data; - if (port->phy_node) + if (port->phyaddr < PHY_MAX_ADDR) if (!port->phy_dev->link) return 0; @@ -5261,7 +5120,7 @@ static int mvpp2_send(struct udevice *dev, void *packet, int length) int tx_done; int timeout; - if (port->phy_node) + if (port->phyaddr < PHY_MAX_ADDR) if (!port->phy_dev->link) return 0; @@ -5445,31 +5304,13 @@ static int mvpp2_probe(struct udevice *dev) { struct mvpp2_port *port = dev_get_priv(dev); struct mvpp2 *priv = dev_get_priv(dev->parent); - struct mii_dev *bus; int err; /* Only call the probe function for the parent once */ if (!priv->probe_done) err = mvpp2_base_probe(dev->parent); - port->priv = dev_get_priv(dev->parent); - - /* Create and register the MDIO bus driver */ - bus = mdio_alloc(); - if (!bus) { - printf("Failed to allocate MDIO bus\n"); - return -ENOMEM; - } - - bus->read = mpp2_mdio_read; - bus->write = mpp2_mdio_write; - snprintf(bus->name, sizeof(bus->name), dev->name); - bus->priv = (void *)port; - port->bus = bus; - - err = mdio_register(bus); - if (err) - return err; + port->priv = priv; err = phy_info_parse(dev, port); if (err) @@ -5498,7 +5339,7 @@ static int mvpp2_probe(struct udevice *dev) port->gop_id * MVPP22_PORT_OFFSET; /* Set phy address of the port */ - if(port->phy_node) + if (port->phyaddr < PHY_MAX_ADDR) mvpp22_smi_phy_addr_cfg(port); /* GoP Init */ From 17caaf8a9d5f9261a58fc7c29eab0ea6fa55e339 Mon Sep 17 00:00:00 2001 From: Nevo Hed Date: Thu, 15 Aug 2019 18:08:45 -0400 Subject: [PATCH 20/60] net: mvpp2: MVPP2 now needs MVMDIO Changes to mvpp2.c require the MVMDIO module which in turn uses DM_MDIO. Signed-off-by: Nevo Hed Reviewed-by: Ramon Fried Acked-by: Joe Hershberger --- drivers/net/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4182897d89..142a2c6953 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -298,6 +298,8 @@ config MVPP2 bool "Marvell Armada 375/7K/8K network interface support" depends on ARMADA_375 || ARMADA_8K select PHYLIB + select MVMDIO + select DM_MDIO help This driver supports the network interface units in the Marvell ARMADA 375, 7K and 8K SoCs. From 945dd965ddd8b27bda6817d3972d8c00a88b8a01 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Sep 2019 19:19:06 +0200 Subject: [PATCH 21/60] net: rtl8169: Support RTL-8168c/8111c This version of the RTL-8168 chip can be found on some add-in cards sold by CSL-Computer GmbH & Co. KG. The chip isn't special in any way, but it needs to have the ChipCmd register programmed after the DMA descriptors have been set up, so make sure that happens by adding an entry to the chip information table. Signed-off-by: Thierry Reding Acked-by: Joe Hershberger --- drivers/net/rtl8169.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 53454f2f21..5ccdfdd683 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -253,6 +253,7 @@ static struct { {"RTL-8169sc/8110sc", 0x18, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x30, 0xff7e1880,}, {"RTL-8168b/8111sb", 0x38, 0xff7e1880,}, + {"RTL-8168c/8111c", 0x3c, 0xff7e1880,}, {"RTL-8168d/8111d", 0x28, 0xff7e1880,}, {"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,}, {"RTL-8168/8111g", 0x4c, 0xff7e1880,}, From 7d9701db40895ff5271220ae852d3631b4500219 Mon Sep 17 00:00:00 2001 From: Ramon Fried Date: Fri, 13 Sep 2019 18:25:03 +0300 Subject: [PATCH 22/60] cmd: mdio/mii: add Kconfig help and allow break dependency * Add Kconfig help describing the purpose of each command. * Add CONFIG_CMD_MDIO so it could be selected individually, as it doesn't depend on the mii command. * Add Kconfig imply to mii to automatically select the mdio command. Signed-off-by: Ramon Fried Acked-by: Joe Hershberger --- cmd/Kconfig | 16 +++++++++++++++- cmd/Makefile | 4 +--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index bc8318d7fa..1e4cf146c5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1473,8 +1473,22 @@ config CMD_NFS config CMD_MII bool "mii" + imply CMD_MDIO help - Enable MII utility commands. + If set, allows 802.3(clause 22) MII Management functions interface access + The management interface specified in Clause 22 provides + a simple, two signal, serial interface to connect a + Station Management entity and a managed PHY for providing access + to management parameters and services. + The interface is referred to as the MII management interface. + +config CMD_MDIO + bool "mdio" + depends on PHYLIB + help + If set, allows Enable 802.3(clause 45) MDIO interface registers access + The MDIO interface is orthogonal to the MII interface and extends + it by adding access to more registers through indirect addressing. config CMD_PING bool "ping" diff --git a/cmd/Makefile b/cmd/Makefile index e87c2f1625..3ac7104546 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -89,9 +89,7 @@ obj-$(CONFIG_CMD_MEMORY) += mem.o obj-$(CONFIG_CMD_IO) += io.o obj-$(CONFIG_CMD_MFSL) += mfsl.o obj-$(CONFIG_CMD_MII) += mii.o -ifdef CONFIG_PHYLIB -obj-$(CONFIG_CMD_MII) += mdio.o -endif +obj-$(CONFIG_CMD_MDIO) += mdio.o obj-$(CONFIG_CMD_MISC) += misc.o obj-$(CONFIG_CMD_MMC) += mmc.o obj-$(CONFIG_MP) += mp.o From 27c3f70f3b50b05051792ef97a7ee13b6a2ed40b Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 30 Sep 2019 10:26:42 +0200 Subject: [PATCH 23/60] net: phy: Increase link up delay in genphy_update_link() I've noticed that in most cases when genphy_update_link() is called, the ethernet driver (mt7628-eth in this case) fails with the first ethernet packets. Resulting in a timeout of the first tftp command. Increasing the delay in the link check look from 1 to 50 ms and moving it below the BMSR register read fixes this issue, resulting in a stable ethernet traffic, even after initial link autonogotiation. Signed-off-by: Stefan Roese Cc: Weijie Gao Cc: Joe Hershberger Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 6be0709e34..80a7664e49 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -256,11 +256,11 @@ int genphy_update_link(struct phy_device *phydev) return -EINTR; } - if ((i++ % 500) == 0) + if ((i++ % 10) == 0) printf("."); - udelay(1000); /* 1 ms */ mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + mdelay(50); /* 50 ms */ } printf(" done\n"); phydev->link = 1; From 0d3044c210c7a7078c4150bfc67927c25ef0d958 Mon Sep 17 00:00:00 2001 From: Josef Holzmayr Date: Wed, 2 Oct 2019 21:22:51 +0200 Subject: [PATCH 24/60] net: macb: explicitly pass phy_adr to mdio read and write To support accessing arbitrary addresses the mii/mdio bus it is necessary that the macb_mdio_read and macb_mdio_write functions do not implicitly use the address of the connected phy. The function signature is extended according to the Linux kernel equivalent. Signed-off-by: Josef Holzmayr Acked-by: Joe Hershberger --- drivers/net/macb.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index f809f3eb07..0f0ede1dc0 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -165,7 +165,8 @@ static int gem_is_gigabit_capable(struct macb_device *macb) return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); } -static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) +static void macb_mdio_write(struct macb_device *macb, u8 phy_adr, u8 reg, + u16 value) { unsigned long netctl; unsigned long netstat; @@ -177,7 +178,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) frame = (MACB_BF(SOF, 1) | MACB_BF(RW, 1) - | MACB_BF(PHYA, macb->phy_addr) + | MACB_BF(PHYA, phy_adr) | MACB_BF(REGA, reg) | MACB_BF(CODE, 2) | MACB_BF(DATA, value)); @@ -192,7 +193,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) macb_writel(macb, NCR, netctl); } -static u16 macb_mdio_read(struct macb_device *macb, u8 reg) +static u16 macb_mdio_read(struct macb_device *macb, u8 phy_adr, u8 reg) { unsigned long netctl; unsigned long netstat; @@ -204,7 +205,7 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg) frame = (MACB_BF(SOF, 1) | MACB_BF(RW, 2) - | MACB_BF(PHYA, macb->phy_addr) + | MACB_BF(PHYA, phy_adr) | MACB_BF(REGA, reg) | MACB_BF(CODE, 2)); macb_writel(macb, MAN, frame); @@ -244,7 +245,7 @@ int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) return -1; arch_get_mdio_control(bus->name); - value = macb_mdio_read(macb, reg); + value = macb_mdio_read(macb, macb->phy_addr, reg); return value; } @@ -264,7 +265,7 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, return -1; arch_get_mdio_control(bus->name); - macb_mdio_write(macb, reg, value); + macb_mdio_write(macb, macb->phy_addr, reg, value); return 0; } @@ -451,13 +452,13 @@ static void macb_phy_reset(struct macb_device *macb, const char *name) u16 status, adv; adv = ADVERTISE_CSMA | ADVERTISE_ALL; - macb_mdio_write(macb, MII_ADVERTISE, adv); + macb_mdio_write(macb, macb->phy_addr, MII_ADVERTISE, adv); printf("%s: Starting autonegotiation...\n", name); - macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE + macb_mdio_write(macb, macb->phy_addr, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (status & BMSR_ANEGCOMPLETE) break; udelay(100); @@ -478,7 +479,7 @@ static int macb_phy_find(struct macb_device *macb, const char *name) /* Search for PHY... */ for (i = 0; i < 32; i++) { macb->phy_addr = i; - phy_id = macb_mdio_read(macb, MII_PHYSID1); + phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); if (phy_id != 0xffff) { printf("%s: PHY present at %d\n", name, i); return 0; @@ -596,7 +597,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) return ret; /* Check if the PHY is up to snuff... */ - phy_id = macb_mdio_read(macb, MII_PHYSID1); + phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1); if (phy_id == 0xffff) { printf("%s: No PHY present\n", name); return -ENODEV; @@ -619,13 +620,13 @@ static int macb_phy_init(struct macb_device *macb, const char *name) phy_config(macb->phydev); #endif - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (!(status & BMSR_LSTATUS)) { /* Try to re-negotiate if we don't have link already. */ macb_phy_reset(macb, name); for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { - status = macb_mdio_read(macb, MII_BMSR); + status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR); if (status & BMSR_LSTATUS) { /* * Delay a bit after the link is established, @@ -646,7 +647,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name) /* First check for GMAC and that it is GiB capable */ if (gem_is_gigabit_capable(macb)) { - lpa = macb_mdio_read(macb, MII_STAT1000); + lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000); if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL | LPA_1000XHALF)) { @@ -680,8 +681,8 @@ static int macb_phy_init(struct macb_device *macb, const char *name) } /* fall back for EMAC checking */ - adv = macb_mdio_read(macb, MII_ADVERTISE); - lpa = macb_mdio_read(macb, MII_LPA); + adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE); + lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA); media = mii_nway_result(lpa & adv); speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0); From 7c56408be61ec5597c944bb67c034e7bf01922d5 Mon Sep 17 00:00:00 2001 From: Josef Holzmayr Date: Wed, 2 Oct 2019 21:22:52 +0200 Subject: [PATCH 25/60] net: macb: let miiphy_read/_write pass arbitrary addresses This allows passing arbitrary addresses through macb_miiphy_read and macb_miiphy_write, therefore enabling the mii command to access all mdio bus devices instead of only the defined phy. Signed-off-by: Josef Holzmayr Acked-by: Joe Hershberger --- drivers/net/macb.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 0f0ede1dc0..8359425378 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -241,11 +241,8 @@ int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) struct macb_device *macb = to_macb(dev); #endif - if (macb->phy_addr != phy_adr) - return -1; - arch_get_mdio_control(bus->name); - value = macb_mdio_read(macb, macb->phy_addr, reg); + value = macb_mdio_read(macb, phy_adr, reg); return value; } @@ -261,11 +258,8 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, struct macb_device *macb = to_macb(dev); #endif - if (macb->phy_addr != phy_adr) - return -1; - arch_get_mdio_control(bus->name); - macb_mdio_write(macb, macb->phy_addr, reg, value); + macb_mdio_write(macb, phy_adr, reg, value); return 0; } From bf58916373f0a94aaf0aca5ee67bb18d5928fa0e Mon Sep 17 00:00:00 2001 From: Florin Chiculita Date: Mon, 14 Oct 2019 17:27:07 +0300 Subject: [PATCH 26/60] net: phy: aquantia: wait for phy init sequence to finish Aquantia quad-phys may take longer to initialize. This commit adds a polling mechanism for a global alarm bit that tells if phy init sequence is completed. Signed-off-by: Florin Chiculita Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 465ec2d342..1061fdfc16 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -37,6 +37,9 @@ #define GLOBAL_FAULT 0xc850 #define GLOBAL_RSTATUS_1 0xc885 +#define GLOBAL_ALARM_1 0xcc00 +#define SYSTEM_READY_BIT 0x40 + #define GLOBAL_STANDARD_CONTROL 0x0 #define SOFT_RESET BIT(15) #define LOW_POWER BIT(11) @@ -258,6 +261,18 @@ int aquantia_config(struct phy_device *phydev) { u32 val, id, rstatus, fault; u32 reg_val1 = 0; + int num_retries = 5; + + /* + * check if the system is out of reset and init sequence completed. + * chip-wide reset for gen1 quad phys takes longer + */ + while (--num_retries) { + rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_ALARM_1); + if (rstatus & SYSTEM_READY_BIT) + break; + mdelay(10); + } id = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_FIRMWARE_ID); rstatus = phy_read(phydev, MDIO_MMD_VEND1, GLOBAL_RSTATUS_1); From 19820db0bd97fd4e202019594abe9a9604aa5534 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 22 Oct 2019 01:03:10 +0200 Subject: [PATCH 27/60] net: eth-uclass: ignore unavailable devices device_probe() may fail in which case the seq_id will be -1. Don't display these devices during startup. While this is only a cosmetic change, the return value of eth_initialize() will also change to the actual number of available devices. The return value is only used in spl_net to decide whether there are any devices to boot from. So returning only available devices is also more correct in that case. Signed-off-by: Michael Walle Acked-by: Joe Hershberger --- net/eth-uclass.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 9fe4096120..ed81cbd537 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -420,20 +420,25 @@ int eth_initialize(void) bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { - if (num_devices) - printf(", "); + if (dev->seq != -1) { + if (num_devices) + printf(", "); - printf("eth%d: %s", dev->seq, dev->name); + printf("eth%d: %s", dev->seq, dev->name); - if (ethprime && dev == prime_dev) - printf(" [PRIME]"); + if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + } eth_write_hwaddr(dev); + if (dev->seq != -1) + num_devices++; uclass_next_device_check(&dev); - num_devices++; } while (dev); + if (!num_devices) + printf("No ethernet found.\n"); putc('\n'); } From b2f2643b393e6aff522dd7f608411a695ea9d67f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 23 Oct 2019 10:46:44 +0000 Subject: [PATCH 28/60] net: phy: micrel: make sure the factory test bit is cleared The KSZ8081 PHY has a factory test mode which is set at the de-assertion of the reset line based on the RXER (KSZ8081RNA/RND) or TXC (KSZ8081MNX/RNB) pin. If a pull-down is missing, or if the pin has a pull-up, the factory test mode should be cleared by manually writing a 0 (according to the datasheet). Create another ksz8081_config function to handle this case. Suggested-by: Antoine Tenart Signed-off-by: Nicolas Ferre Acked-by: Joe Hershberger --- drivers/net/phy/micrel_ksz8xxx.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c index daa57ce33c..e27fc45a28 100644 --- a/drivers/net/phy/micrel_ksz8xxx.c +++ b/drivers/net/phy/micrel_ksz8xxx.c @@ -24,6 +24,7 @@ static struct phy_driver KSZ804_driver = { }; #define MII_KSZPHY_OMSO 0x16 +#define KSZPHY_OMSO_FACTORY_TEST BIT(15) #define KSZPHY_OMSO_B_CAST_OFF (1 << 9) static int ksz_genconfig_bcastoff(struct phy_device *phydev) @@ -80,12 +81,30 @@ static struct phy_driver KSZ8051_driver = { .shutdown = &genphy_shutdown, }; +static int ksz8081_config(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO); + if (ret < 0) + return ret; + + ret &= ~KSZPHY_OMSO_FACTORY_TEST; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, + ret | KSZPHY_OMSO_B_CAST_OFF); + if (ret < 0) + return ret; + + return genphy_config(phydev); +} + static struct phy_driver KSZ8081_driver = { .name = "Micrel KSZ8081", .uid = 0x221560, .mask = 0xfffff0, .features = PHY_BASIC_FEATURES, - .config = &ksz_genconfig_bcastoff, + .config = &ksz8081_config, .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; From f41a722baa9fab4eb6843eca51f0318ad104f145 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 27 Oct 2019 01:14:37 +0200 Subject: [PATCH 29/60] net: phy: mv88e61xx: rework to enable detection of 88E6071 devices Extend the driver to init switch register offsets from variables instead of compile time macros and enable detection of 88E6071 and compatible devices. Ethernet transfer (e.g. tftp) does not work yet, so enable the registration of the 'indirect mii' bus for easier PHY register access by 'mii' command. Signed-off-by: Anatolij Gustschin Acked-by: Joe Hershberger --- drivers/net/phy/mv88e61xx.c | 150 ++++++++++++++++++++++++++++++------ 1 file changed, 125 insertions(+), 25 deletions(-) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index c1e2860329..9aba04253c 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -39,15 +39,11 @@ #define PHY_AUTONEGOTIATE_TIMEOUT 5000 -#define PORT_COUNT 11 -#define PORT_MASK ((1 << PORT_COUNT) - 1) +#define PORT_MASK(port_count) ((1 << (port_count)) - 1) /* Device addresses */ #define DEVADDR_PHY(p) (p) -#define DEVADDR_PORT(p) (0x10 + (p)) #define DEVADDR_SERDES 0x0F -#define DEVADDR_GLOBAL_1 0x1B -#define DEVADDR_GLOBAL_2 0x1C /* SMI indirection registers for multichip addressing mode */ #define SMI_CMD_REG 0x00 @@ -182,17 +178,26 @@ #endif /* ID register values for different switch models */ +#define PORT_SWITCH_ID_6020 0x0200 +#define PORT_SWITCH_ID_6070 0x0700 +#define PORT_SWITCH_ID_6071 0x0710 #define PORT_SWITCH_ID_6096 0x0980 #define PORT_SWITCH_ID_6097 0x0990 #define PORT_SWITCH_ID_6172 0x1720 #define PORT_SWITCH_ID_6176 0x1760 +#define PORT_SWITCH_ID_6220 0x2200 #define PORT_SWITCH_ID_6240 0x2400 +#define PORT_SWITCH_ID_6250 0x2500 #define PORT_SWITCH_ID_6352 0x3520 struct mv88e61xx_phy_priv { struct mii_dev *mdio_bus; int smi_addr; int id; + int port_count; /* Number of switch ports */ + int port_reg_base; /* Base of the switch port registers */ + u8 global1; /* Offset of Switch Global 1 registers */ + u8 global2; /* Offset of Switch Global 2 registers */ }; static inline int smi_cmd(int cmd, int addr, int reg) @@ -329,11 +334,12 @@ static int mv88e61xx_reg_write(struct phy_device *phydev, int dev, int reg, static int mv88e61xx_phy_wait(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; u32 timeout = 100; do { - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2, + val = mv88e61xx_reg_read(phydev, priv->global2, GLOBAL2_REG_PHY_CMD); if (val >= 0 && (val & SMI_BUSY) == 0) return 0; @@ -347,13 +353,15 @@ static int mv88e61xx_phy_wait(struct phy_device *phydev) static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev, int devad, int reg) { + struct mv88e61xx_phy_priv *priv; struct phy_device *phydev; int res; phydev = (struct phy_device *)smi_wrapper->priv; + priv = phydev->priv; /* Issue command to read */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_CMD, smi_cmd_read(dev, reg)); @@ -363,25 +371,27 @@ static int mv88e61xx_phy_read_indirect(struct mii_dev *smi_wrapper, int dev, return res; /* Read retrieved data */ - return mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_2, + return mv88e61xx_reg_read(phydev, priv->global2, GLOBAL2_REG_PHY_DATA); } static int mv88e61xx_phy_write_indirect(struct mii_dev *smi_wrapper, int dev, int devad, int reg, u16 data) { + struct mv88e61xx_phy_priv *priv; struct phy_device *phydev; int res; phydev = (struct phy_device *)smi_wrapper->priv; + priv = phydev->priv; /* Set the data to write */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_DATA, data); if (res < 0) return res; /* Issue the write command */ - res = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_2, + res = mv88e61xx_reg_write(phydev, priv->global2, GLOBAL2_REG_PHY_CMD, smi_cmd_write(dev, reg)); if (res < 0) @@ -408,13 +418,18 @@ static int mv88e61xx_phy_write(struct phy_device *phydev, int phy, static int mv88e61xx_port_read(struct phy_device *phydev, u8 port, u8 reg) { - return mv88e61xx_reg_read(phydev, DEVADDR_PORT(port), reg); + struct mv88e61xx_phy_priv *priv = phydev->priv; + + return mv88e61xx_reg_read(phydev, priv->port_reg_base + port, reg); } static int mv88e61xx_port_write(struct phy_device *phydev, u8 port, u8 reg, u16 val) { - return mv88e61xx_reg_write(phydev, DEVADDR_PORT(port), reg, val); + struct mv88e61xx_phy_priv *priv = phydev->priv; + + return mv88e61xx_reg_write(phydev, priv->port_reg_base + port, + reg, val); } static int mv88e61xx_set_page(struct phy_device *phydev, u8 phy, u8 page) @@ -515,12 +530,13 @@ static int mv88e61xx_parse_status(struct phy_device *phydev) static int mv88e61xx_switch_reset(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int time; int val; u8 port; /* Disable all ports */ - for (port = 0; port < PORT_COUNT; port++) { + for (port = 0; port < priv->port_count; port++) { val = mv88e61xx_port_read(phydev, port, PORT_REG_CTRL); if (val < 0) return val; @@ -536,19 +552,19 @@ static int mv88e61xx_switch_reset(struct phy_device *phydev) udelay(2000); /* Reset switch */ - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_CTRL); if (val < 0) return val; val |= GLOBAL1_CTRL_SWRESET; - val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_CTRL, val); + val = mv88e61xx_reg_write(phydev, priv->global1, + GLOBAL1_CTRL, val); if (val < 0) return val; /* Wait up to 1 second for switch reset complete */ for (time = 1000; time; time--) { - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, + GLOBAL1_CTRL); if (val >= 0 && ((val & GLOBAL1_CTRL_SWRESET) == 0)) break; udelay(1000); @@ -732,22 +748,23 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) static int mv88e61xx_set_cpu_port(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; /* Set CPUDest */ - val = mv88e61xx_reg_read(phydev, DEVADDR_GLOBAL_1, GLOBAL1_MON_CTRL); + val = mv88e61xx_reg_read(phydev, priv->global1, GLOBAL1_MON_CTRL); if (val < 0) return val; val = bitfield_replace(val, GLOBAL1_MON_CTRL_CPUDEST_SHIFT, GLOBAL1_MON_CTRL_CPUDEST_WIDTH, CONFIG_MV88E61XX_CPU_PORT); - val = mv88e61xx_reg_write(phydev, DEVADDR_GLOBAL_1, - GLOBAL1_MON_CTRL, val); + val = mv88e61xx_reg_write(phydev, priv->global1, + GLOBAL1_MON_CTRL, val); if (val < 0) return val; /* Allow CPU to route to any port */ - val = PORT_MASK & ~(1 << CONFIG_MV88E61XX_CPU_PORT); + val = PORT_MASK(priv->port_count) & ~(1 << CONFIG_MV88E61XX_CPU_PORT); val = mv88e61xx_port_set_vlan(phydev, CONFIG_MV88E61XX_CPU_PORT, val); if (val < 0) return val; @@ -856,6 +873,48 @@ static int mv88e61xx_phy_config_port(struct phy_device *phydev, u8 phy) return 0; } +/* + * This function is used to pre-configure the required register + * offsets, so that the indirect register access to the PHY registers + * is possible. This is necessary to be able to read the PHY ID + * while driver probing or in get_phy_id(). The globalN register + * offsets must be initialized correctly for a detected switch, + * otherwise detection of the PHY ID won't work! + */ +static int mv88e61xx_priv_reg_offs_pre_init(struct phy_device *phydev) +{ + struct mv88e61xx_phy_priv *priv = phydev->priv; + + /* + * Initial 'port_reg_base' value must be an offset of existing + * port register, then reading the ID should succeed. First, try + * to read via port registers with device address 0x10 (88E6096 + * and compatible switches). + */ + priv->port_reg_base = 0x10; + priv->id = mv88e61xx_get_switch_id(phydev); + if (priv->id != 0xfff0) { + priv->global1 = 0x1B; + priv->global2 = 0x1C; + return 0; + } + + /* + * Now try via port registers with device address 0x08 + * (88E6020 and compatible switches). + */ + priv->port_reg_base = 0x08; + priv->id = mv88e61xx_get_switch_id(phydev); + if (priv->id != 0xfff0) { + priv->global1 = 0x0F; + priv->global2 = 0x07; + return 0; + } + + debug("%s Unknown ID 0x%x\n", __func__, priv->id); + return -ENODEV; +} + static int mv88e61xx_probe(struct phy_device *phydev) { struct mii_dev *smi_wrapper; @@ -910,13 +969,43 @@ static int mv88e61xx_probe(struct phy_device *phydev) phydev->priv = priv; - priv->id = mv88e61xx_get_switch_id(phydev); + res = mv88e61xx_priv_reg_offs_pre_init(phydev); + if (res < 0) + return res; + + debug("%s ID 0x%x\n", __func__, priv->id); + + switch (priv->id) { + case PORT_SWITCH_ID_6096: + case PORT_SWITCH_ID_6097: + case PORT_SWITCH_ID_6172: + case PORT_SWITCH_ID_6176: + case PORT_SWITCH_ID_6240: + case PORT_SWITCH_ID_6352: + priv->port_count = 11; + break; + case PORT_SWITCH_ID_6020: + case PORT_SWITCH_ID_6070: + case PORT_SWITCH_ID_6071: + case PORT_SWITCH_ID_6220: + case PORT_SWITCH_ID_6250: + priv->port_count = 7; + break; + default: + free(priv); + return -ENODEV; + } + + res = mdio_register(smi_wrapper); + if (res) + printf("Failed to register SMI bus\n"); return 0; } static int mv88e61xx_phy_config(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int res; int i; int ret = -1; @@ -925,7 +1014,7 @@ static int mv88e61xx_phy_config(struct phy_device *phydev) if (res < 0) return res; - for (i = 0; i < PORT_COUNT; i++) { + for (i = 0; i < priv->port_count; i++) { if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) { phydev->addr = i; @@ -988,13 +1077,14 @@ static int mv88e61xx_phy_is_connected(struct phy_device *phydev) static int mv88e61xx_phy_startup(struct phy_device *phydev) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int i; int link = 0; int res; int speed = phydev->speed; int duplex = phydev->duplex; - for (i = 0; i < PORT_COUNT; i++) { + for (i = 0; i < priv->port_count; i++) { if ((1 << i) & CONFIG_MV88E61XX_PHY_PORTS) { phydev->addr = i; if (!mv88e61xx_phy_is_connected(phydev)) @@ -1068,6 +1158,16 @@ int get_phy_id(struct mii_dev *bus, int smi_addr, int devad, u32 *phy_id) temp_phy.priv = &temp_priv; temp_mii.priv = &temp_phy; + /* + * get_phy_id() can be called by framework before mv88e61xx driver + * probing, in this case the global register offsets are not + * initialized yet. Do this initialization here before indirect + * PHY register access. + */ + val = mv88e61xx_priv_reg_offs_pre_init(&temp_phy); + if (val < 0) + return val; + val = mv88e61xx_phy_read_indirect(&temp_mii, 0, devad, MII_PHYSID1); if (val < 0) return -EIO; From 4aa05f6cf3e893ba2394d81e586400872e3303c1 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 27 Oct 2019 01:14:38 +0200 Subject: [PATCH 30/60] net: phy: mv88e61xx: add CPU port parameter init for 88E6071 On 88E6071 chip the port status register bit field offsets for duplex and link bits differ. Extend the driver to use 88E6071 specific offset values. The width of bit fields for speed status differ, too. Adapt for proper port speed detection on 88E6071. Signed-off-by: Anatolij Gustschin Reviewed-by: Chris Packham Tested-by: Chris Packham Acked-by: Joe Hershberger --- drivers/net/phy/mv88e61xx.c | 42 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index 9aba04253c..63675e4e68 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -84,11 +84,7 @@ #define GLOBAL1_MON_CTRL_CPUDEST_SHIFT 4 #define GLOBAL1_MON_CTRL_CPUDEST_WIDTH 4 -#define PORT_REG_STATUS_LINK BIT(11) -#define PORT_REG_STATUS_DUPLEX BIT(10) - #define PORT_REG_STATUS_SPEED_SHIFT 8 -#define PORT_REG_STATUS_SPEED_WIDTH 2 #define PORT_REG_STATUS_SPEED_10 0 #define PORT_REG_STATUS_SPEED_100 1 #define PORT_REG_STATUS_SPEED_1000 2 @@ -107,6 +103,7 @@ #define PORT_REG_PHYS_CTRL_DUPLEX_VALUE BIT(3) #define PORT_REG_PHYS_CTRL_DUPLEX_FORCE BIT(2) #define PORT_REG_PHYS_CTRL_SPD1000 BIT(1) +#define PORT_REG_PHYS_CTRL_SPD100 BIT(0) #define PORT_REG_PHYS_CTRL_SPD_MASK (BIT(1) | BIT(0)) #define PORT_REG_CTRL_PSTATE_SHIFT 0 @@ -196,6 +193,9 @@ struct mv88e61xx_phy_priv { int id; int port_count; /* Number of switch ports */ int port_reg_base; /* Base of the switch port registers */ + u16 port_stat_link_mask;/* Bitmask for port link status bits */ + u16 port_stat_dup_mask; /* Bitmask for port duplex status bits */ + u8 port_stat_speed_width;/* Width of speed status bitfield */ u8 global1; /* Offset of Switch Global 1 registers */ u8 global2; /* Offset of Switch Global 2 registers */ }; @@ -644,6 +644,7 @@ static int mv88e61xx_port_set_vlan(struct phy_device *phydev, u8 port, static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int res; int val; bool forced = false; @@ -651,7 +652,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) val = mv88e61xx_port_read(phydev, port, PORT_REG_STATUS); if (val < 0) return val; - if (!(val & PORT_REG_STATUS_LINK)) { + if (!(val & priv->port_stat_link_mask)) { /* Temporarily force link to read port configuration */ u32 timeout = 100; forced = true; @@ -674,7 +675,7 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) res = -EIO; goto unforce; } - if (val & PORT_REG_STATUS_LINK) + if (val & priv->port_stat_link_mask) break; } while (--timeout); @@ -684,13 +685,13 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port) } } - if (val & PORT_REG_STATUS_DUPLEX) + if (val & priv->port_stat_dup_mask) phydev->duplex = DUPLEX_FULL; else phydev->duplex = DUPLEX_HALF; val = bitfield_extract(val, PORT_REG_STATUS_SPEED_SHIFT, - PORT_REG_STATUS_SPEED_WIDTH); + priv->port_stat_speed_width); switch (val) { case PORT_REG_STATUS_SPEED_1000: phydev->speed = SPEED_1000; @@ -723,6 +724,7 @@ unforce: static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; val = mv88e61xx_port_read(phydev, port, PORT_REG_PHYS_CTRL); @@ -730,13 +732,19 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port) return val; val &= ~(PORT_REG_PHYS_CTRL_SPD_MASK | - PORT_REG_PHYS_CTRL_FC_VALUE); - val |= PORT_REG_PHYS_CTRL_PCS_AN_EN | - PORT_REG_PHYS_CTRL_PCS_AN_RST | - PORT_REG_PHYS_CTRL_FC_FORCE | + PORT_REG_PHYS_CTRL_FC_VALUE | + PORT_REG_PHYS_CTRL_FC_FORCE); + val |= PORT_REG_PHYS_CTRL_FC_FORCE | PORT_REG_PHYS_CTRL_DUPLEX_VALUE | - PORT_REG_PHYS_CTRL_DUPLEX_FORCE | - PORT_REG_PHYS_CTRL_SPD1000; + PORT_REG_PHYS_CTRL_DUPLEX_FORCE; + + if (priv->id == PORT_SWITCH_ID_6071) { + val |= PORT_REG_PHYS_CTRL_SPD100; + } else { + val |= PORT_REG_PHYS_CTRL_PCS_AN_EN | + PORT_REG_PHYS_CTRL_PCS_AN_RST | + PORT_REG_PHYS_CTRL_SPD1000; + } if (port == CONFIG_MV88E61XX_CPU_PORT) val |= PORT_REG_PHYS_CTRL_LINK_VALUE | @@ -983,6 +991,9 @@ static int mv88e61xx_probe(struct phy_device *phydev) case PORT_SWITCH_ID_6240: case PORT_SWITCH_ID_6352: priv->port_count = 11; + priv->port_stat_link_mask = BIT(11); + priv->port_stat_dup_mask = BIT(10); + priv->port_stat_speed_width = 2; break; case PORT_SWITCH_ID_6020: case PORT_SWITCH_ID_6070: @@ -990,6 +1001,9 @@ static int mv88e61xx_probe(struct phy_device *phydev) case PORT_SWITCH_ID_6220: case PORT_SWITCH_ID_6250: priv->port_count = 7; + priv->port_stat_link_mask = BIT(12); + priv->port_stat_dup_mask = BIT(9); + priv->port_stat_speed_width = 1; break; default: free(priv); From 41820c4baa74f4c71d53e554ca2078763cdaa6e8 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 27 Oct 2019 01:14:39 +0200 Subject: [PATCH 31/60] net: phy: mv88E61xx: fix ENERGY_DET init for mv88E6071 On mv88E6071 the 'EDet' field offset, width and sense control bits are different, adjust the driver to init the PHY control register as needed. This fixes not working link detection and tftp transfers. Signed-off-by: Anatolij Gustschin Reviewed-by: Chris Packham Tested-by: Chris Packham Acked-by: Joe Hershberger --- drivers/net/phy/mv88e61xx.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index 63675e4e68..07d0896823 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -117,14 +117,12 @@ #define SERDES_REG_CTRL_1_FORCE_LINK BIT(10) -#define PHY_REG_CTRL1_ENERGY_DET_SHIFT 8 -#define PHY_REG_CTRL1_ENERGY_DET_WIDTH 2 - /* Field values */ #define PORT_REG_CTRL_PSTATE_DISABLED 0 #define PORT_REG_CTRL_PSTATE_FORWARD 3 #define PHY_REG_CTRL1_ENERGY_DET_OFF 0 +#define PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE 1 #define PHY_REG_CTRL1_ENERGY_DET_SENSE_ONLY 2 #define PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT 3 @@ -198,6 +196,9 @@ struct mv88e61xx_phy_priv { u8 port_stat_speed_width;/* Width of speed status bitfield */ u8 global1; /* Offset of Switch Global 1 registers */ u8 global2; /* Offset of Switch Global 2 registers */ + u8 phy_ctrl1_en_det_shift; /* 'EDet' bit field offset */ + u8 phy_ctrl1_en_det_width; /* Width of 'EDet' bit field */ + u8 phy_ctrl1_en_det_ctrl; /* 'EDet' control value */ }; static inline int smi_cmd(int cmd, int addr, int reg) @@ -846,6 +847,7 @@ static int mv88e61xx_phy_enable(struct phy_device *phydev, u8 phy) static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy) { + struct mv88e61xx_phy_priv *priv = phydev->priv; int val; /* @@ -855,9 +857,9 @@ static int mv88e61xx_phy_setup(struct phy_device *phydev, u8 phy) val = mv88e61xx_phy_read(phydev, phy, PHY_REG_CTRL1); if (val < 0) return val; - val = bitfield_replace(val, PHY_REG_CTRL1_ENERGY_DET_SHIFT, - PHY_REG_CTRL1_ENERGY_DET_WIDTH, - PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT); + val = bitfield_replace(val, priv->phy_ctrl1_en_det_shift, + priv->phy_ctrl1_en_det_width, + priv->phy_ctrl1_en_det_ctrl); val = mv88e61xx_phy_write(phydev, phy, PHY_REG_CTRL1, val); if (val < 0) return val; @@ -994,6 +996,10 @@ static int mv88e61xx_probe(struct phy_device *phydev) priv->port_stat_link_mask = BIT(11); priv->port_stat_dup_mask = BIT(10); priv->port_stat_speed_width = 2; + priv->phy_ctrl1_en_det_shift = 8; + priv->phy_ctrl1_en_det_width = 2; + priv->phy_ctrl1_en_det_ctrl = + PHY_REG_CTRL1_ENERGY_DET_SENSE_XMIT; break; case PORT_SWITCH_ID_6020: case PORT_SWITCH_ID_6070: @@ -1004,6 +1010,10 @@ static int mv88e61xx_probe(struct phy_device *phydev) priv->port_stat_link_mask = BIT(12); priv->port_stat_dup_mask = BIT(9); priv->port_stat_speed_width = 1; + priv->phy_ctrl1_en_det_shift = 14; + priv->phy_ctrl1_en_det_width = 1; + priv->phy_ctrl1_en_det_ctrl = + PHY_REG_CTRL1_ENERGY_DET_SENSE_PULSE; break; default: free(priv); From 5bcb4b8ff646f5c340c6d06c8f84b082963f5f8d Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 27 Oct 2019 01:14:40 +0200 Subject: [PATCH 32/60] net: phy: mv88e61xx: register phy_driver struct for 88E6071 Support probing and init for 88E6071 switch. Signed-off-by: Anatolij Gustschin Reviewed-by: Chris Packham Tested-by: Chris Packham Acked-by: Joe Hershberger --- drivers/net/phy/mv88e61xx.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index 07d0896823..5aff7ed397 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -1154,10 +1154,22 @@ static struct phy_driver mv88e609x_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver mv88e6071_driver = { + .name = "Marvell MV88E6071", + .uid = 0x1410db0, + .mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES | SUPPORTED_MII, + .probe = mv88e61xx_probe, + .config = mv88e61xx_phy_config, + .startup = mv88e61xx_phy_startup, + .shutdown = &genphy_shutdown, +}; + int phy_mv88e61xx_init(void) { phy_register(&mv88e61xx_driver); phy_register(&mv88e609x_driver); + phy_register(&mv88e6071_driver); return 0; } From 389488df92f08eed95149e66562d29db634af6a3 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Sun, 27 Oct 2019 01:14:41 +0200 Subject: [PATCH 33/60] net: phy: fix switch vendor name Fix vendor name in MV88E61xx option description. Signed-off-by: Anatolij Gustschin Reviewed-by: Chris Packham Tested-by: Chris Packham Acked-by: Joe Hershberger --- drivers/net/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bcea8a0c3e..dceea1516f 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -46,7 +46,7 @@ config B53_PHY_PORTS endif # B53_SWITCH config MV88E61XX_SWITCH - bool "Marvel MV88E61xx Ethernet switch PHY support." + bool "Marvell MV88E61xx Ethernet switch PHY support." if MV88E61XX_SWITCH From 17285fc2833e0db04a2bd3d411cdf1a3e387de83 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:28 +0200 Subject: [PATCH 34/60] include: phy: define XFI and USXGMII interface types Drivers currently use XGMII for XFI and USXGMII and, where needed, use other information to identify the actual protocol on the board. With these two defined drivers can now rely on DT phy-mode property. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- include/phy_interface.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/phy_interface.h b/include/phy_interface.h index c6823189f8..73f3a3679c 100644 --- a/include/phy_interface.h +++ b/include/phy_interface.h @@ -31,6 +31,8 @@ typedef enum { PHY_INTERFACE_MODE_XLAUI, PHY_INTERFACE_MODE_CAUI2, PHY_INTERFACE_MODE_CAUI4, + PHY_INTERFACE_MODE_XFI, + PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_NONE, /* Must be last */ PHY_INTERFACE_MODE_COUNT, @@ -58,6 +60,8 @@ static const char * const phy_interface_strings[] = { [PHY_INTERFACE_MODE_XLAUI] = "xlaui4", [PHY_INTERFACE_MODE_CAUI2] = "caui2", [PHY_INTERFACE_MODE_CAUI4] = "caui4", + [PHY_INTERFACE_MODE_XFI] = "xfi", + [PHY_INTERFACE_MODE_USXGMII] = "usxgmii", [PHY_INTERFACE_MODE_NONE] = "", }; From d718b697a1794876511d6a30a047acfce0b69312 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:29 +0200 Subject: [PATCH 35/60] include: phy: add data field for private driver data This is useful to carry custom information between the driver structure associated with a specific HW and the driver code. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- include/phy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/phy.h b/include/phy.h index e50f56b6eb..6ace9b3a0c 100644 --- a/include/phy.h +++ b/include/phy.h @@ -115,6 +115,9 @@ struct phy_driver { u16 val); struct list_head list; + + /* driver private data */ + ulong data; }; struct phy_device { From 8a141d6e9cc1841082e4c996703eafb037ec63ad Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:30 +0200 Subject: [PATCH 36/60] drivers: net: aquantia: use XFI, USXGMII interface types The PHY supports XFI and USXGMII, the notable difference being that USX AN is enabled for USXGMII. Legacy code uses XGMII for any 10G proto and detects whether USX AN should be enabled or not using a PHY status register. Keep that functionality too, so we don't break existing drivers. Signed-off-by: Razvan Ionut Cirjan Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 47 ++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 1061fdfc16..601121dc3a 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -259,9 +259,11 @@ static int aquantia_upload_firmware(struct phy_device *phydev) int aquantia_config(struct phy_device *phydev) { + int interface = phydev->interface; u32 val, id, rstatus, fault; u32 reg_val1 = 0; int num_retries = 5; + int usx_an = 0; /* * check if the system is out of reset and init sequence completed. @@ -293,17 +295,34 @@ int aquantia_config(struct phy_device *phydev) if (ret != 0) return ret; } + /* + * for backward compatibility convert XGMII into either XFI or USX based + * on FW config + */ + if (interface == PHY_INTERFACE_MODE_XGMII) { + reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, + AQUANTIA_SYSTEM_INTERFACE_SR); + if ((reg_val1 & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) + interface = PHY_INTERFACE_MODE_USXGMII; + else + interface = PHY_INTERFACE_MODE_XFI; + } val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR); - if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: /* 1000BASE-T mode */ phydev->advertising = SUPPORTED_1000baseT_Full; phydev->supported = phydev->advertising; val = (val & ~AQUNTIA_SPEED_LSB_MASK) | AQUNTIA_SPEED_MSB_MASK; phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val); - } else if (phydev->interface == PHY_INTERFACE_MODE_XGMII) { + break; + case PHY_INTERFACE_MODE_USXGMII: + usx_an = 1; + /* FALLTHROUGH */ + case PHY_INTERFACE_MODE_XFI: /* 10GBASE-T mode */ phydev->advertising = SUPPORTED_10000baseT_Full; phydev->supported = phydev->advertising; @@ -314,40 +333,40 @@ int aquantia_config(struct phy_device *phydev) AQUNTIA_SPEED_LSB_MASK | AQUNTIA_SPEED_MSB_MASK); - val = phy_read(phydev, MDIO_MMD_PHYXS, - AQUANTIA_SYSTEM_INTERFACE_SR); /* If SI is USXGMII then start USXGMII autoneg */ - if ((val & AQUANTIA_SI_IN_USE_MASK) == AQUANTIA_SI_USXGMII) { - reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, - AQUANTIA_VENDOR_PROVISIONING_REG); + reg_val1 = phy_read(phydev, MDIO_MMD_PHYXS, + AQUANTIA_VENDOR_PROVISIONING_REG); + if (usx_an) { reg_val1 |= AQUANTIA_USX_AUTONEG_CONTROL_ENA; - - phy_write(phydev, MDIO_MMD_PHYXS, - AQUANTIA_VENDOR_PROVISIONING_REG, - reg_val1); printf("%s: system interface USXGMII\n", phydev->dev->name); } else { + reg_val1 &= ~AQUANTIA_USX_AUTONEG_CONTROL_ENA; printf("%s: system interface XFI\n", phydev->dev->name); } - } else if (phydev->interface == PHY_INTERFACE_MODE_SGMII_2500) { + phy_write(phydev, MDIO_MMD_PHYXS, + AQUANTIA_VENDOR_PROVISIONING_REG, reg_val1); + break; + case PHY_INTERFACE_MODE_SGMII_2500: /* 2.5GBASE-T mode */ phydev->advertising = SUPPORTED_1000baseT_Full; phydev->supported = phydev->advertising; phy_write(phydev, MDIO_MMD_AN, AQUNTIA_10G_CTL, 1); phy_write(phydev, MDIO_MMD_AN, AQUNTIA_VENDOR_P1, 0x9440); - } else if (phydev->interface == PHY_INTERFACE_MODE_MII) { + break; + case PHY_INTERFACE_MODE_MII: /* 100BASE-TX mode */ phydev->advertising = SUPPORTED_100baseT_Full; phydev->supported = phydev->advertising; val = (val & ~AQUNTIA_SPEED_MSB_MASK) | AQUNTIA_SPEED_LSB_MASK; phy_write(phydev, MDIO_MMD_PMAPMD, MII_BMCR, val); - } + break; + }; val = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_RESERVED_STATUS); reg_val1 = phy_read(phydev, MDIO_MMD_VEND1, AQUANTIA_FIRMWARE_ID); From 5fe861b8b25b574af9e403be77fcfcf8c86e892b Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:31 +0200 Subject: [PATCH 37/60] drivers: net: aquantia: add PHY generation information Uses the data field in phy_driver structure to identify the PHY generation. This is useful for custom configuration as non-generic PHY registers are not 100% compatible between generations. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 601121dc3a..397abc0380 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -72,6 +72,12 @@ #define VERSION_STRING_OFFSET 0x0200 #define HEADER_OFFSET 0x300 +/* driver private data */ +#define AQUANTIA_NA 0 +#define AQUANTIA_GEN1 1 +#define AQUANTIA_GEN2 2 +#define AQUANTIA_GEN3 3 + #pragma pack(1) struct fw_header { u8 padding[4]; @@ -467,6 +473,7 @@ struct phy_driver aqr105_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN1, }; struct phy_driver aqr106_driver = { @@ -493,6 +500,7 @@ struct phy_driver aqr107_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN2, }; struct phy_driver aqr112_driver = { @@ -506,6 +514,7 @@ struct phy_driver aqr112_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN3, }; struct phy_driver aqr405_driver = { @@ -519,6 +528,7 @@ struct phy_driver aqr405_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN1, }; struct phy_driver aqr412_driver = { @@ -532,6 +542,7 @@ struct phy_driver aqr412_driver = { .config = &aquantia_config, .startup = &aquantia_startup, .shutdown = &gen10g_shutdown, + .data = AQUANTIA_GEN3, }; int phy_aquantia_init(void) From a301ec7a5a165e3bfd2a33509dbd87dab0559e72 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:32 +0200 Subject: [PATCH 38/60] drivers: net: aquantia: set up SI protocol based on interface type If PHY is not ready for data by the time _config is called, reconfigure the PHY system interface to use the proper protocol based on phydev->interface, just in case the defaults set by PHY firmware don't match current configuration. Signed-off-by: Florin Laurentiu Chiculita Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 107 +++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 397abc0380..d166d05d5b 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -21,6 +21,7 @@ #define AQUNTIA_SPEED_MSB_MASK 0x40 #define AQUANTIA_SYSTEM_INTERFACE_SR 0xe812 +#define AQUANTIA_SYSTEM_INTERFACE_SR_READY BIT(0) #define AQUANTIA_VENDOR_PROVISIONING_REG 0xC441 #define AQUANTIA_FIRMWARE_ID 0x20 #define AQUANTIA_RESERVED_STATUS 0xc885 @@ -33,6 +34,9 @@ #define AQUANTIA_SI_USXGMII 0x0018 /* registers in MDIO_MMD_VEND1 region */ +#define AQUANTIA_VND1_GLOBAL_SC 0x000 +#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb) + #define GLOBAL_FIRMWARE_ID 0x20 #define GLOBAL_FAULT 0xc850 #define GLOBAL_RSTATUS_1 0xc885 @@ -63,6 +67,26 @@ #define UP_RUN_STALL_OVERRIDE BIT(6) #define UP_RUN_STALL BIT(0) +/* + * global start rate, the protocol associated with this speed is used by default + * on SI. + */ +#define AQUANTIA_VND1_GSTART_RATE 0x31a +#define AQUANTIA_VND1_GSTART_RATE_OFF 0 +#define AQUANTIA_VND1_GSTART_RATE_100M 1 +#define AQUANTIA_VND1_GSTART_RATE_1G 2 +#define AQUANTIA_VND1_GSTART_RATE_10G 3 +#define AQUANTIA_VND1_GSTART_RATE_2_5G 4 +#define AQUANTIA_VND1_GSTART_RATE_5G 5 + +/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */ +#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b +#define AQUANTIA_VND1_GSYSCFG_100M 0 +#define AQUANTIA_VND1_GSYSCFG_1G 1 +#define AQUANTIA_VND1_GSYSCFG_2_5G 2 +#define AQUANTIA_VND1_GSYSCFG_5G 3 +#define AQUANTIA_VND1_GSYSCFG_10G 4 + /* addresses of memory segments in the phy */ #define DRAM_BASE_ADDR 0x3FFE0000 #define IRAM_BASE_ADDR 0x40000000 @@ -263,6 +287,68 @@ static int aquantia_upload_firmware(struct phy_device *phydev) } #endif +struct { + u16 syscfg; + int cnt; + u16 start_rate; +} aquantia_syscfg[PHY_INTERFACE_MODE_COUNT] = { + [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G, + AQUANTIA_VND1_GSTART_RATE_1G}, + [PHY_INTERFACE_MODE_SGMII_2500] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G, + AQUANTIA_VND1_GSTART_RATE_2_5G}, + [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, + [PHY_INTERFACE_MODE_XFI] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, + [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G, + AQUANTIA_VND1_GSTART_RATE_10G}, +}; + +static int aquantia_set_proto(struct phy_device *phydev) +{ + int i; + + if (!aquantia_syscfg[phydev->interface].cnt) + return 0; + + /* set the default rate to enable the SI link */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, + aquantia_syscfg[phydev->interface].start_rate); + + /* set selected protocol for all relevant line side link speeds */ + for (i = 0; i <= aquantia_syscfg[phydev->interface].cnt; i++) + phy_write(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i, + aquantia_syscfg[phydev->interface].syscfg); + return 0; +} + +static bool aquantia_link_is_up(struct phy_device *phydev) +{ + u16 reg, regmask; + int devad, regnum; + + /* + * On Gen 2 and 3 we have a bit that indicates that both system and + * line side are ready for data, use that if possible. + */ + if (phydev->drv->data == AQUANTIA_GEN2 || + phydev->drv->data == AQUANTIA_GEN3) { + devad = MDIO_MMD_PHYXS; + regnum = AQUANTIA_SYSTEM_INTERFACE_SR; + regmask = AQUANTIA_SYSTEM_INTERFACE_SR_READY; + } else { + devad = MDIO_MMD_AN; + regnum = MDIO_STAT1; + regmask = MDIO_AN_STAT1_COMPLETE; + } + /* the register should be latched, do a double read */ + phy_read(phydev, devad, regnum); + reg = phy_read(phydev, devad, regnum); + + return !!(reg & regmask); +} + int aquantia_config(struct phy_device *phydev) { int interface = phydev->interface; @@ -314,6 +400,27 @@ int aquantia_config(struct phy_device *phydev) interface = PHY_INTERFACE_MODE_XFI; } + /* + * if link is up already we can just use it, otherwise configure + * the protocols in the PHY. If link is down set the system + * interface protocol to use based on phydev->interface + */ + if (!aquantia_link_is_up(phydev) && + (phydev->drv->data == AQUANTIA_GEN2 || + phydev->drv->data == AQUANTIA_GEN3)) { + /* set PHY in low power mode so we can configure protocols */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, + AQUANTIA_VND1_GLOBAL_SC_LP); + mdelay(10); + + /* configure protocol based on phydev->interface */ + aquantia_set_proto(phydev); + + /* wake PHY back up */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); + mdelay(10); + } + val = phy_read(phydev, MDIO_MMD_PMAPMD, MII_BMCR); switch (interface) { From 7552ee9a01b838b95a1d486355b40dfe1ed2ad2f Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:33 +0200 Subject: [PATCH 39/60] drivers: net: aquantia: set MDI reversal based on DT property MDI pins up to the RJ45 connector may be reversed on the board and the default PHY configuration applied by firmware may or may not match that. Add an optional DT property to configure MDI reversal for this case. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index d166d05d5b..3b036d01c7 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -67,6 +67,13 @@ #define UP_RUN_STALL_OVERRIDE BIT(6) #define UP_RUN_STALL BIT(0) +#define AQUANTIA_PMA_RX_VENDOR_P1 0xe400 +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK GENMASK(1, 0) +/* MDI reversal configured through registers */ +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG BIT(1) +/* MDI reversal enabled */ +#define AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV BIT(0) + /* * global start rate, the protocol associated with this speed is used by default * on SI. @@ -323,6 +330,36 @@ static int aquantia_set_proto(struct phy_device *phydev) return 0; } +static int aquantia_dts_config(struct phy_device *phydev) +{ +#ifdef CONFIG_DM_ETH + ofnode node = phydev->node; + u32 prop; + u16 reg; + + /* this code only works on gen2 and gen3 PHYs */ + if (phydev->drv->data != AQUANTIA_GEN2 && + phydev->drv->data != AQUANTIA_GEN3) + return -ENOTSUPP; + + if (!ofnode_valid(node)) + return 0; + + if (!ofnode_read_u32(node, "mdi-reversal", &prop)) { + debug("mdi-reversal = %d\n", (int)prop); + reg = phy_read(phydev, MDIO_MMD_PMAPMD, + AQUANTIA_PMA_RX_VENDOR_P1); + reg &= ~AQUANTIA_PMA_RX_VENDOR_P1_MDI_MSK; + reg |= AQUANTIA_PMA_RX_VENDOR_P1_MDI_CFG; + reg |= prop ? AQUANTIA_PMA_RX_VENDOR_P1_MDI_REV : 0; + phy_write(phydev, MDIO_MMD_PMAPMD, AQUANTIA_PMA_RX_VENDOR_P1, + reg); + } + +#endif + return 0; +} + static bool aquantia_link_is_up(struct phy_device *phydev) { u16 reg, regmask; @@ -415,6 +452,8 @@ int aquantia_config(struct phy_device *phydev) /* configure protocol based on phydev->interface */ aquantia_set_proto(phydev); + /* apply custom configuration based on DT */ + aquantia_dts_config(phydev); /* wake PHY back up */ phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); From 05f86070c0722015520ceb172b22070db5d0aa35 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:34 +0200 Subject: [PATCH 40/60] drivers: net: aquantia: set SMBus addr based on DT property Aquantia PHYs have a SMBus interface mostly used for debug. The addresses on this interface are normally set up by PHY firmware, but depending on the board they may end up not being unique. Add an optional DT property used to change SMBus address if needed. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 3b036d01c7..3992a97712 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -94,6 +94,9 @@ #define AQUANTIA_VND1_GSYSCFG_5G 3 #define AQUANTIA_VND1_GSYSCFG_10G 4 +#define AQUANTIA_VND1_SMBUS0 0xc485 +#define AQUANTIA_VND1_SMBUS1 0xc495 + /* addresses of memory segments in the phy */ #define DRAM_BASE_ADDR 0x3FFE0000 #define IRAM_BASE_ADDR 0x40000000 @@ -355,6 +358,18 @@ static int aquantia_dts_config(struct phy_device *phydev) phy_write(phydev, MDIO_MMD_PMAPMD, AQUANTIA_PMA_RX_VENDOR_P1, reg); } + if (!ofnode_read_u32(node, "smb-addr", &prop)) { + debug("smb-addr = %x\n", (int)prop); + /* + * there are two addresses here, normally just one bus would + * be in use so we're setting both regs using the same DT + * property. + */ + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS0, + (u16)(prop << 1)); + phy_write(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_SMBUS1, + (u16)(prop << 1)); + } #endif return 0; From 6d9bc2043a5ee95bebbe57dfe6c034d60a607a7b Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:35 +0200 Subject: [PATCH 41/60] drivers: net: aquantia: check system interface too when checking for link up In some cases the link on the system interface of the aquantia PHY comes up after the link on line interface. The link state loop only checks the line side, which may result in first packet sent being lost. Use aquantia_link_is_up instead, which checks both system and line side on gen 2/3 PHYs to avoid losing the 1st packet. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/phy/aquantia.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 3992a97712..c4bd443001 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -555,17 +555,14 @@ int aquantia_startup(struct phy_device *phydev) phydev->duplex = DUPLEX_FULL; /* if the AN is still in progress, wait till timeout. */ - phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); - reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); - if (!(reg & MDIO_AN_STAT1_COMPLETE)) { + if (!aquantia_link_is_up(phydev)) { printf("%s Waiting for PHY auto negotiation to complete", phydev->dev->name); do { udelay(1000); - reg = phy_read(phydev, MDIO_MMD_AN, MDIO_STAT1); if ((i++ % 500) == 0) printf("."); - } while (!(reg & MDIO_AN_STAT1_COMPLETE) && + } while (!aquantia_link_is_up(phydev) && i < (4 * PHY_ANEG_TIMEOUT)); if (i > PHY_ANEG_TIMEOUT) From e81031c2b8062c865b88cd6d39e86a55591a2c1f Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:36 +0200 Subject: [PATCH 42/60] doc: bindings: add bindings document for PHY nodes It defines that PHY nodes must be children on MDIO bus nodes and defines the only required property in U-Boot, reg. This property along with the example provided are copied over from Linux. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/phy.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 doc/device-tree-bindings/net/phy.txt diff --git a/doc/device-tree-bindings/net/phy.txt b/doc/device-tree-bindings/net/phy.txt new file mode 100644 index 0000000000..6599c667b5 --- /dev/null +++ b/doc/device-tree-bindings/net/phy.txt @@ -0,0 +1,24 @@ +PHY nodes + +If the device tree is used to describe networking interfaces, U-Boot expects a +node for each PHY. Parent node for such a PHY node is expected to correspond to +a MDIO bus and the bus is used to access the PHY. + +Required properties: + + - reg : The ID number for the phy, usually a small integer + +Example: + +ethernet-phy@0 { + compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22"; + interrupt-parent = <&PIC>; + interrupts = <35 IRQ_TYPE_EDGE_RISING>; + reg = <0>; + + resets = <&rst 8>; + reset-names = "phy"; + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + reset-assert-us = <1000>; + reset-deassert-us = <2000>; +}; From ee278acdf1d5ed7ac670e2ccf5184417da6ca264 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:37 +0200 Subject: [PATCH 43/60] doc: bindings: Aquantia PHY node binding A couple of optional properties have been introduced for Aquantia PHY allowing the driver to set up wiring related configuration points that are otherwise driven by firmware. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- doc/device-tree-bindings/net/aquantia-phy.txt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 doc/device-tree-bindings/net/aquantia-phy.txt diff --git a/doc/device-tree-bindings/net/aquantia-phy.txt b/doc/device-tree-bindings/net/aquantia-phy.txt new file mode 100644 index 0000000000..89ce61e05b --- /dev/null +++ b/doc/device-tree-bindings/net/aquantia-phy.txt @@ -0,0 +1,25 @@ +PHY nodes for Aquantia devices. + +This text describes properties that are applicable to Aquantia PHY nodes in +addition to the bindings in phy.txt. + +Aquantia PHYs allow some flexibility in the way they are wired in a system, +they allow MDI pins to be reversed, LEDs linked up in different weays, have an +I2C slave interface that can be used for debug. Normally the configuration +corresponding to these is driven by the PHY firmware with the downside that +a custom firmware is needed for each integration of a PHY. +Several optional bindings are defined that allow these configuration points to +be driven by the PHY driver and reduce dependency on specific FW versions. + +Optional properties: +mdi-reversal: 0 or 1 indicating that reversal must be disabled/enabled. + Firmware default is used if the property is missing. +smb-addr: I2C/SMBus address to use, firmware default is used if the property + is missing. + +Example node: +phy@00 { + reg = <0x00>; + mdi-reversal = <1>; + smb-addr = <0x25>; +}; From e22e3aff923937add30f7f800197c9f5713ea611 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:28:38 +0200 Subject: [PATCH 44/60] drivers: net: fsl_enetc: use XFI, USXGMII interface type macros Apply 10G PCS init for USXGMII, XFI interface types. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index 0ca7e838a8..a7740deb6f 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -197,6 +197,8 @@ static void enetc_start_pcs(struct udevice *dev) enetc_init_rgmii(dev); break; case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_XFI: enetc_init_sxgmii(dev); break; }; From 16cdc2daa07986243751a9f545aa287c60e04ced Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Sat, 23 Nov 2019 17:58:59 +0000 Subject: [PATCH 45/60] net: tftp: Fix too small block size Commit b618b3707633 ("net: Convert CONFIG_TFTP_BLOCKSIZE to Kconfig") accidentally set the default *option* TFTP block size to 512 bytes, even though the comment in the code says that this is a terrible choice. Most boards didn't define the symbol before, so they got the default block size of 1468 bytes before, but now use 512 bytes, which is also the fallback. This leads to both abysmal performance and a lot of hashes printed on the screen (one character for every 5K), which is both annoying and slow over serial links. Set the default block size in Kconfig back to the value it had before. This improves TFTP performance from 2.8 MB/s to 6.9 MB/s on a Pine64. Fixes: b618b3707633 ("net: Convert CONFIG_TFTP_BLOCKSIZE to Kconfig") Signed-off-by: Andre Przywara Acked-by: Joe Hershberger --- net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/Kconfig b/net/Kconfig index 68cecf75a2..a07f6746c5 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -31,7 +31,7 @@ config IP_DEFRAG config TFTP_BLOCKSIZE int "TFTP block size" - default 512 + default 1468 help Default TFTP block size. From a5d32c37d9eec2f819273536a5600a0fbde09acb Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Mon, 25 Nov 2019 17:15:11 +0200 Subject: [PATCH 46/60] net: mdio-uclass: rename arguments of dm_mdio_phy_connect for clarity Renamed dm_mdio_phy_connect arguments dev to mdiodev and addr to phyaddr for a bit more clarity and consistency with the following patches. Also use NULL instead of 0 on error return path. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- include/miiphy.h | 6 +++--- net/mdio-uclass.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/miiphy.h b/include/miiphy.h index 9b97d09f18..94bf0da24a 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -154,14 +154,14 @@ void dm_mdio_probe_devices(void); /** * dm_mdio_phy_connect - Wrapper over phy_connect for DM MDIO * - * @dev: mdio dev - * @addr: PHY address on MDIO bus + * @mdiodev: mdio device the PHY is accesible on + * @phyaddr: PHY address on MDIO bus * @ethdev: ethernet device to connect to the PHY * @interface: MAC-PHY protocol * * @return pointer to phy_device, or 0 on error */ -struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface); diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 6f922e80b6..7a5f1d6dcc 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -104,16 +104,16 @@ static int dm_mdio_pre_remove(struct udevice *dev) return 0; } -struct phy_device *dm_mdio_phy_connect(struct udevice *dev, int addr, +struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface) { - struct mdio_perdev_priv *pdata = dev_get_uclass_priv(dev); + struct mdio_perdev_priv *pdata = dev_get_uclass_priv(mdiodev); - if (device_probe(dev)) - return 0; + if (device_probe(mdiodev)) + return NULL; - return phy_connect(pdata->mii_bus, addr, ethdev, interface); + return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); } UCLASS_DRIVER(mdio) = { From 2f6245594e1f11db00efcaa5ac122918f019e0b4 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Mon, 25 Nov 2019 17:15:12 +0200 Subject: [PATCH 47/60] net: mdio-uclass: add dm_eth_phy_connect helper function The function connects an ethernet device to a PHY using DT information. This API is only available for eth devices with an associated device tree node. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- include/miiphy.h | 12 +++++++ net/mdio-uclass.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/include/miiphy.h b/include/miiphy.h index 94bf0da24a..61c136b114 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -165,6 +165,18 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, struct udevice *ethdev, phy_interface_t interface); +/** + * dm_eth_phy_connect - Connect an Eth device to a PHY based on device tree + * + * Picks up the DT phy-handle and phy-mode from ethernet device node and + * connects the ethernet device to the linked PHY. + * + * @ethdev: ethernet device + * + * @return pointer to phy_device, or 0 on error + */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev); + #endif #ifdef CONFIG_DM_MDIO_MUX diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c index 7a5f1d6dcc..f75e4df626 100644 --- a/net/mdio-uclass.c +++ b/net/mdio-uclass.c @@ -10,6 +10,16 @@ #include #include +/* DT node properties for MAC-PHY interface */ +#define PHY_MODE_STR_CNT 2 +static const char *phy_mode_str[PHY_MODE_STR_CNT] = { "phy-mode", + "phy-connection-type" }; +/* DT node properties that reference a PHY node */ +#define PHY_HANDLE_STR_CNT 3 +const char *phy_handle_str[PHY_HANDLE_STR_CNT] = { "phy-handle", + "phy", + "phy-device" }; + void dm_mdio_probe_devices(void) { struct udevice *it; @@ -116,6 +126,86 @@ struct phy_device *dm_mdio_phy_connect(struct udevice *mdiodev, int phyaddr, return phy_connect(pdata->mii_bus, phyaddr, ethdev, interface); } +static struct phy_device *dm_eth_connect_phy_handle(struct udevice *ethdev, + phy_interface_t interface) +{ + u32 phy_addr; + struct udevice *mdiodev; + struct phy_device *phy; + struct ofnode_phandle_args phandle = {.node = ofnode_null()}; + int i; + + for (i = 0; i < PHY_HANDLE_STR_CNT; i++) + if (!dev_read_phandle_with_args(ethdev, phy_handle_str[i], NULL, + 0, 0, &phandle)) + break; + + if (!ofnode_valid(phandle.node)) { + dev_dbg(dev, "can't find PHY node\n"); + return NULL; + } + + /* + * reading 'reg' directly should be fine. This is a PHY node, the + * address is always size 1 and requires no translation + */ + if (ofnode_read_u32(phandle.node, "reg", &phy_addr)) { + dev_dbg(ethdev, "missing reg property in phy node\n"); + return NULL; + } + + if (uclass_get_device_by_ofnode(UCLASS_MDIO, + ofnode_get_parent(phandle.node), + &mdiodev)) { + dev_dbg(dev, "can't find MDIO bus for node %s\n", + ofnode_get_name(ofnode_get_parent(phandle.node))); + return NULL; + } + + phy = dm_mdio_phy_connect(mdiodev, phy_addr, ethdev, interface); + + if (phy) + phy->node = phandle.node; + + return phy; +} + +/* Connect to a PHY linked in eth DT node */ +struct phy_device *dm_eth_phy_connect(struct udevice *ethdev) +{ + const char *if_str; + phy_interface_t interface; + struct phy_device *phy; + int i; + + if (!ofnode_valid(ethdev->node)) { + debug("%s: supplied eth dev has no DT node!\n", ethdev->name); + return NULL; + } + + interface = PHY_INTERFACE_MODE_NONE; + for (i = 0; i < PHY_MODE_STR_CNT; i++) { + if_str = ofnode_read_string(ethdev->node, phy_mode_str[i]); + if (if_str) { + interface = phy_get_interface_by_name(if_str); + break; + } + } + if (interface < 0) + interface = PHY_INTERFACE_MODE_NONE; + if (interface == PHY_INTERFACE_MODE_NONE) + dev_dbg(ethdev, "can't find interface mode, default to NONE\n"); + + phy = dm_eth_connect_phy_handle(ethdev, interface); + + if (!phy) + return NULL; + + phy->interface = interface; + + return phy; +} + UCLASS_DRIVER(mdio) = { .id = UCLASS_MDIO, .name = "mdio", From 17bd7eae72fed240ff806c14b53fd6ff281ee311 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Mon, 25 Nov 2019 17:15:13 +0200 Subject: [PATCH 48/60] drivers: net: fsl_enetc: use the new MDIO DM helper functions Uses the new dm_eth_phy_connect helper to connect to the PHY to simplify the code. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc.c | 53 +++++++---------------------------------- drivers/net/fsl_enetc.h | 1 + 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index a7740deb6f..c94ba240f8 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -205,57 +205,20 @@ static void enetc_start_pcs(struct udevice *dev) } /* Configure the actual/external ethernet PHY, if one is found */ -static void enetc_start_phy(struct udevice *dev) +static void enetc_config_phy(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); - struct udevice *miidev; - struct phy_device *phy; - u32 phandle, phy_id; - ofnode phy_node; int supported; - if (!ofnode_valid(dev->node)) { - enetc_dbg(dev, "no enetc ofnode found, skipping PHY set-up\n"); - return; - } + priv->phy = dm_eth_phy_connect(dev); - if (ofnode_read_u32(dev->node, "phy-handle", &phandle)) { - enetc_dbg(dev, "phy-handle not found, skipping PHY set-up\n"); + if (!priv->phy) return; - } - - phy_node = ofnode_get_by_phandle(phandle); - if (!ofnode_valid(phy_node)) { - enetc_dbg(dev, "invalid phy node, skipping PHY set-up\n"); - return; - } - enetc_dbg(dev, "phy node: %s\n", ofnode_get_name(phy_node)); - - if (ofnode_read_u32(phy_node, "reg", &phy_id)) { - enetc_dbg(dev, - "missing reg in PHY node, skipping PHY set-up\n"); - return; - } - - if (uclass_get_device_by_ofnode(UCLASS_MDIO, - ofnode_get_parent(phy_node), - &miidev)) { - enetc_dbg(dev, "can't find MDIO bus for node %s\n", - ofnode_get_name(ofnode_get_parent(phy_node))); - return; - } - - phy = dm_mdio_phy_connect(miidev, phy_id, dev, priv->if_type); - if (!phy) { - enetc_dbg(dev, "dm_mdio_phy_connect returned null\n"); - return; - } supported = GENMASK(6, 0); /* speeds up to 1G & AN */ - phy->advertising = phy->supported & supported; - phy->node = phy_node; - phy_config(phy); - phy_startup(phy); + priv->phy->advertising = priv->phy->supported & supported; + + phy_config(priv->phy); } /* @@ -470,7 +433,9 @@ static int enetc_start(struct udevice *dev) enetc_setup_rx_bdr(dev); enetc_start_pcs(dev); - enetc_start_phy(dev); + enetc_config_phy(dev); + if (priv->phy) + phy_startup(priv->phy); return 0; } diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 0bb4cdff47..9a36cdad80 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -154,6 +154,7 @@ struct enetc_priv { int if_type; struct mii_dev imdio; + struct phy_device *phy; }; /* register accessors */ From 307f8a6d1f034fc23aa7a42fa121f7fa011a33e4 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:58:45 +0200 Subject: [PATCH 49/60] drivers: net: fsl_enetc: Add 2.5Gbps to supported link speeds The original code enabled link speeds up to 1Gbps, but the interface can go up to 2.5G, enable that speed to in PHY AN mask. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index c94ba240f8..64dc244da2 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -215,8 +215,9 @@ static void enetc_config_phy(struct udevice *dev) if (!priv->phy) return; - supported = GENMASK(6, 0); /* speeds up to 1G & AN */ - priv->phy->advertising = priv->phy->supported & supported; + supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; + priv->phy->supported &= supported; + priv->phy->advertising &= supported; phy_config(priv->phy); } From a931f78307300070e3a6cb95958f7dcc5fce3bb6 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:58:46 +0200 Subject: [PATCH 50/60] drivers: net: fsl_enetc: move PCS and PHY config to probe This reduces the time needed to establish a link as we don't reset the link each time the interface is used. Our Link capabilities do not change at run-time so there is no need to re-apply PHY configuration each time. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index 64dc244da2..e86f3dddb5 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -190,12 +190,6 @@ static void enetc_start_pcs(struct udevice *dev) case PHY_INTERFACE_MODE_SGMII_2500: enetc_init_sgmii(dev); break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - enetc_init_rgmii(dev); - break; case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_USXGMII: case PHY_INTERFACE_MODE_XFI: @@ -258,6 +252,9 @@ static int enetc_probe(struct udevice *dev) dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY); + enetc_start_pcs(dev); + enetc_config_phy(dev); + return 0; } @@ -433,8 +430,12 @@ static int enetc_start(struct udevice *dev) enetc_setup_tx_bdr(dev); enetc_setup_rx_bdr(dev); - enetc_start_pcs(dev); - enetc_config_phy(dev); + if (priv->if_type == PHY_INTERFACE_MODE_RGMII || + priv->if_type == PHY_INTERFACE_MODE_RGMII_ID || + priv->if_type == PHY_INTERFACE_MODE_RGMII_RXID || + priv->if_type == PHY_INTERFACE_MODE_RGMII_TXID) + enetc_init_rgmii(dev); + if (priv->phy) phy_startup(priv->phy); From 6c9644685940e1d98c2d38fb205e8da14f3690b5 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Thu, 14 Nov 2019 18:58:47 +0200 Subject: [PATCH 51/60] drivers: net: fsl_enetc_mdio: return with time-out if HW is stuck On some boards MDIO may get stuck if it detects echo on the line. This is a know hardware issue, there is a board fix for it. In case we're running on a board that doesn't have the fix, we don't want to loop here forever and freeze U-Boot. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc_mdio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c index b4463a58a5..47257a6cf6 100644 --- a/drivers/net/fsl_enetc_mdio.c +++ b/drivers/net/fsl_enetc_mdio.c @@ -17,8 +17,13 @@ static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv) { - while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) + int to = 10000; + + while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) && + --to) cpu_relax(); + if (!to) + printf("T"); } int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad, From 1e354cb3931472c6e88aa6c46d4bda9beddfdcc4 Mon Sep 17 00:00:00 2001 From: Alex Marginean Date: Mon, 25 Nov 2019 17:57:27 +0200 Subject: [PATCH 52/60] drivers: net: fsl_enetc: register internal MDIO bus This bus is used to access internal SoC PHYs. These PHYs are configured by the ENETC driver directly, but it's useful to have command line access to this MDIO to debug the system especially when using new external PHYs. Signed-off-by: Alex Marginean Acked-by: Joe Hershberger --- drivers/net/fsl_enetc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index e86f3dddb5..02c1ee70d9 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -156,19 +156,14 @@ static void enetc_start_pcs(struct udevice *dev) priv->if_type = PHY_INTERFACE_MODE_NONE; - /* check internal mdio capability, not all ports need it */ + /* register internal MDIO for debug purposes */ if (enetc_read_port(priv, ENETC_PCAPR0) & ENETC_PCAPRO_MDIO) { - /* - * set up internal MDIO, this is part of ETH PCI function and is - * used to access serdes / internal SoC PHYs. - * We don't currently register it as a MDIO bus as it goes away - * when the interface is removed, so it can't practically be - * used in the console. - */ priv->imdio.read = enetc_mdio_read; priv->imdio.write = enetc_mdio_write; priv->imdio.priv = priv->port_regs + ENETC_PM_IMDIO_BASE; strncpy(priv->imdio.name, dev->name, MDIO_NAME_LEN); + if (!miiphy_get_dev_by_name(priv->imdio.name)) + mdio_register(&priv->imdio); } if (!ofnode_valid(dev->node)) { @@ -451,6 +446,10 @@ static void enetc_stop(struct udevice *dev) { /* FLR is sufficient to quiesce the device */ dm_pci_flr(dev); + /* leave the BARs accessible after we stop, this is needed to use + * internal MDIO in command line. + */ + dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY); } /* From 08b3e90a0168c9053c9bdd7df5d187cb6668a4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 28 Nov 2019 13:37:04 +0100 Subject: [PATCH 53/60] net: ftgmac100: align RX/TX descriptors on ARCH_DMA_MINALIGN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: e766849713ff ("net: ftgmac100: convert the RX/TX descriptor arrays") Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Acked-by: Joe Hershberger --- drivers/net/ftgmac100.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index b6b8a93bb5..ebb74339b2 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -72,8 +72,8 @@ enum ftgmac100_model { struct ftgmac100_data { struct ftgmac100 *iobase; - struct ftgmac100_txdes txdes[PKTBUFSTX]; - struct ftgmac100_rxdes rxdes[PKTBUFSRX]; + struct ftgmac100_txdes txdes[PKTBUFSTX] __aligned(ARCH_DMA_MINALIGN); + struct ftgmac100_rxdes rxdes[PKTBUFSRX] __aligned(ARCH_DMA_MINALIGN); int tx_index; int rx_index; @@ -310,7 +310,7 @@ static int ftgmac100_start(struct udevice *dev) } priv->txdes[PKTBUFSTX - 1].txdes0 = priv->txdes0_edotr_mask; - start = (ulong)&priv->txdes[0]; + start = ((ulong)&priv->txdes[0]) & ~(ARCH_DMA_MINALIGN - 1); end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN); flush_dcache_range(start, end); @@ -320,7 +320,7 @@ static int ftgmac100_start(struct udevice *dev) } priv->rxdes[PKTBUFSRX - 1].rxdes0 = priv->rxdes0_edorr_mask; - start = (ulong)&priv->rxdes[0]; + start = ((ulong)&priv->rxdes[0]) & ~(ARCH_DMA_MINALIGN - 1); end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN); flush_dcache_range(start, end); @@ -370,7 +370,7 @@ static int ftgmac100_free_pkt(struct udevice *dev, uchar *packet, int length) { struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); @@ -392,7 +392,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100_rxdes *curr_des = &priv->rxdes[priv->rx_index]; unsigned short rxlen; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); ulong data_start = curr_des->rxdes3; @@ -427,7 +427,7 @@ static int ftgmac100_recv(struct udevice *dev, int flags, uchar **packetp) static u32 ftgmac100_read_txdesc(const void *desc) { const struct ftgmac100_txdes *txdes = desc; - ulong des_start = (ulong)txdes; + ulong des_start = ((ulong)txdes) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*txdes), ARCH_DMA_MINALIGN); invalidate_dcache_range(des_start, des_end); @@ -445,7 +445,7 @@ static int ftgmac100_send(struct udevice *dev, void *packet, int length) struct ftgmac100_data *priv = dev_get_priv(dev); struct ftgmac100 *ftgmac100 = priv->iobase; struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; - ulong des_start = (ulong)curr_des; + ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1); ulong des_end = des_start + roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN); ulong data_start; From b8a4dd28f3b719d176fed5dc8d23a898463b072c Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:20 +0530 Subject: [PATCH 54/60] dma: Introduce dma_get_cfg() interface Sometimes, there would be a need to exchange data between DMA provider and DMA client which are very specific to DMA driver of the SoC/platform and are not generic enough to be put into struct dma. Therefore, introduce dma_get_cfg() interface to get DMA provider specific data from client device. Clients can use unique configuration ID flags to get different configuration data from DMA driver. Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- drivers/dma/dma-uclass.c | 12 ++++++++++++ include/dma-uclass.h | 11 +++++++++++ include/dma.h | 12 ++++++++++++ 3 files changed, 35 insertions(+) diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c index 0ff56f7e88..5598bca21c 100644 --- a/drivers/dma/dma-uclass.c +++ b/drivers/dma/dma-uclass.c @@ -187,6 +187,18 @@ int dma_send(struct dma *dma, void *src, size_t len, void *metadata) return ops->send(dma, src, len, metadata); } + +int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data) +{ + struct dma_ops *ops = dma_dev_ops(dma->dev); + + debug("%s(dma=%p)\n", __func__, dma); + + if (!ops->get_cfg) + return -ENOSYS; + + return ops->get_cfg(dma, cfg_id, cfg_data); +} #endif /* CONFIG_DMA_CHANNELS */ int dma_get_device(u32 transfer_type, struct udevice **devp) diff --git a/include/dma-uclass.h b/include/dma-uclass.h index 31b43fb4b9..a1d9d26ac5 100644 --- a/include/dma-uclass.h +++ b/include/dma-uclass.h @@ -108,6 +108,17 @@ struct dma_ops { * @return zero on success, or -ve error code. */ int (*send)(struct dma *dma, void *src, size_t len, void *metadata); + /** + * get_cfg() - Get DMA channel configuration for client's use + * + * @dma: The DMA Channel to manipulate + * @cfg_id: DMA provider specific ID to identify what + * configuration data client needs + * @data: Pointer to store pointer to DMA driver specific + * configuration data for the given cfg_id (output param) + * @return zero on success, or -ve error code. + */ + int (*get_cfg)(struct dma *dma, u32 cfg_id, void **data); #endif /* CONFIG_DMA_CHANNELS */ /** * transfer() - Issue a DMA transfer. The implementation must diff --git a/include/dma.h b/include/dma.h index d1c3d0df7d..6c55aa3a00 100644 --- a/include/dma.h +++ b/include/dma.h @@ -290,6 +290,18 @@ int dma_receive(struct dma *dma, void **dst, void *metadata); * @return zero on success, or -ve error code. */ int dma_send(struct dma *dma, void *src, size_t len, void *metadata); + +/** + * dma_get_cfg() - Get DMA channel configuration for client's use + * + * @dma: The DMA Channel to manipulate + * @cfg_id: DMA provider specific ID to identify what + * configuration data client needs + * @cfg_data: Pointer to store pointer to DMA driver specific + * configuration data for the given cfg_id (output param) + * @return zero on success, or -ve error code. + */ +int dma_get_cfg(struct dma *dma, u32 cfg_id, void **cfg_data); #endif /* CONFIG_DMA_CHANNELS */ /* From 5e6d9ccde9cf700e19e0d783f1f671a1eb4a60fb Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:21 +0530 Subject: [PATCH 55/60] dma: ti: k3-udma: Implement dma_get_cfg() interface Implement dma_get_cfg() interface to pass flow id information for DMA clients to use. This is needed because on K3 SoCs, CPSW (ethernet) and UDMA (DMA provider) support "flows" within a given RX DMA channel. This allows different network packets to be segregated while using same RX DMA channel. In order for basic ethernet to work, CPSW slave must be aware of the flow ID allocated for the RX channel by the DMA driver. This interface allows CPSW to query flow ID from DMA provider and configure it in CPSW HW. Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- drivers/dma/ti/k3-udma.c | 28 ++++++++++++++++++++++++++++ include/linux/soc/ti/ti-udma.h | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 2e64d338ca..f90ca53e90 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -104,6 +104,8 @@ struct udma_chan { struct udma_rchan *rchan; struct udma_rflow *rflow; + struct ti_udma_drv_chan_cfg_data cfg_data; + u32 bcnt; /* number of bytes completed since the start of the channel */ bool pkt_mode; /* TR or packet */ @@ -1407,6 +1409,11 @@ static int udma_request(struct dma *dma) uc->desc_rx_cur = 0; uc->num_rx_bufs = 0; + if (uc->dir == DMA_DEV_TO_MEM) { + uc->cfg_data.flow_id_base = uc->rflow->id; + uc->cfg_data.flow_id_cnt = 1; + } + return 0; } @@ -1689,6 +1696,26 @@ int udma_prepare_rcv_buf(struct dma *dma, void *dst, size_t size) return 0; } +static int udma_get_cfg(struct dma *dma, u32 id, void **data) +{ + struct udma_dev *ud = dev_get_priv(dma->dev); + struct udma_chan *uc; + + if (dma->id >= (ud->rchan_cnt + ud->tchan_cnt)) { + dev_err(dma->dev, "invalid dma ch_id %lu\n", dma->id); + return -EINVAL; + } + + switch (id) { + case TI_UDMA_CHAN_PRIV_INFO: + uc = &ud->channels[dma->id]; + *data = &uc->cfg_data; + return 0; + } + + return -EINVAL; +} + static const struct dma_ops udma_ops = { .transfer = udma_transfer, .of_xlate = udma_of_xlate, @@ -1699,6 +1726,7 @@ static const struct dma_ops udma_ops = { .send = udma_send, .receive = udma_receive, .prepare_rcv_buf = udma_prepare_rcv_buf, + .get_cfg = udma_get_cfg, }; static const struct udevice_id udma_ids[] = { diff --git a/include/linux/soc/ti/ti-udma.h b/include/linux/soc/ti/ti-udma.h index e9d4226c48..04e354fb2d 100644 --- a/include/linux/soc/ti/ti-udma.h +++ b/include/linux/soc/ti/ti-udma.h @@ -21,4 +21,23 @@ struct ti_udma_drv_packet_data { u32 dest_tag; }; +/** + * struct ti_udma_drv_chan_cfg_data - TI UDMA per channel specific + * configuration data + * + * @flow_id_base: Start index of flow ID allocated to this channel + * @flow_id_cnt: Number of flows allocated for this channel starting at + * flow_id_base + * + * TI UDMA channel specific data returned as part of dma_get_cfg() call + * from the DMA client driver. + */ +struct ti_udma_drv_chan_cfg_data { + u32 flow_id_base; + u32 flow_id_cnt; +}; + +/* TI UDMA specific flag IDs for dma_get_cfg() call */ +#define TI_UDMA_CHAN_PRIV_INFO 0 + #endif /* __TI_UDMA_H */ From 461a290c5afbbb00dcbd671bedcad13abea9b37a Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:22 +0530 Subject: [PATCH 56/60] net: ti: am65-cpsw-nuss: Rework RX flow ID handling Get flow ID information for RX DMA channel using dma_get_cfg() interface instead of reading from DT. This is required in order to avoid DT update whenever there is change in the range of flow ID allocated to the host. Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- drivers/net/ti/am65-cpsw-nuss.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 06b0663950..db686595b7 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -99,7 +99,6 @@ struct am65_cpsw_common { u32 port_num; struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS]; - u32 rflow_id_base; struct mii_dev *bus; u32 bus_freq; @@ -276,6 +275,7 @@ static int am65_cpsw_start(struct udevice *dev) struct am65_cpsw_common *common = priv->cpsw_common; struct am65_cpsw_port *port = &common->ports[priv->port_id]; struct am65_cpsw_port *port0 = &common->ports[0]; + struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data; int ret, i; ret = power_domain_on(&common->pwrdmn); @@ -341,8 +341,11 @@ static int am65_cpsw_start(struct udevice *dev) writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG); /* set base flow_id */ - writel(common->rflow_id_base, + dma_get_cfg(&common->dma_rx, 0, (void **)&dma_rx_cfg_data); + writel(dma_rx_cfg_data->flow_id_base, port0->port_base + AM65_CPSW_P0_FLOW_ID_REG); + dev_info(dev, "K3 CPSW: rflow_id_base: %u\n", + dma_rx_cfg_data->flow_id_base); /* Reset and enable the ALE */ writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL | @@ -669,11 +672,6 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) AM65_CPSW_CPSW_NU_ALE_BASE; cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; - cpsw_common->rflow_id_base = 0; - cpsw_common->rflow_id_base = - dev_read_u32_default(dev, "ti,rx-flow-id-base", - cpsw_common->rflow_id_base); - ports_np = dev_read_subnode(dev, "ports"); if (!ofnode_valid(ports_np)) { ret = -ENOENT; @@ -761,12 +759,11 @@ static int am65_cpsw_probe_cpsw(struct udevice *dev) if (ret) goto out; - dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u rflow_id_base:%u mdio_freq:%u\n", + dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u mdio_freq:%u\n", readl(cpsw_common->ss_base), readl(cpsw_common->cpsw_base), readl(cpsw_common->ale_base), cpsw_common->port_num, - cpsw_common->rflow_id_base, cpsw_common->bus_freq); out: From 382c0c629e75b6213b638f734db468e23ca4cff3 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:23 +0530 Subject: [PATCH 57/60] net: ti: am65-cpsw-nuss: Add new compatible for J721e Add new compatible to handle J721e SoC Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- drivers/dma/ti/k3-udma.c | 1 + drivers/net/ti/am65-cpsw-nuss.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index f90ca53e90..f7128610c5 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -1731,6 +1731,7 @@ static const struct dma_ops udma_ops = { static const struct udevice_id udma_ids[] = { { .compatible = "ti,k3-navss-udmap" }, + { .compatible = "ti,j721e-navss-mcu-udmap" }, { } }; diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index db686595b7..2590486810 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -774,6 +774,7 @@ out: static const struct udevice_id am65_cpsw_nuss_ids[] = { { .compatible = "ti,am654-cpsw-nuss" }, + { .compatible = "ti,j721e-cpsw-nuss" }, { } }; From 4886f1cb5956910554cec6779307496d91bad283 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:24 +0530 Subject: [PATCH 58/60] arm: dts: k3-j721e-common-proc-board: Add DMA and CPSW related DT nodes Add DT nodes related to DMA and CPSW to -u-boot.dtsi to get networking up on J721e EVM. Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- .../k3-j721e-common-proc-board-u-boot.dtsi | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi index 541da22c48..9291e57e25 100644 --- a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi +++ b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi @@ -3,11 +3,18 @@ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ */ +#include +#include + / { chosen { stdout-path = "serial2:115200n8"; tick-timer = &timer1; }; + + aliases { + ethernet0 = &cpsw_port1; + }; }; &cbass_main{ @@ -24,6 +31,184 @@ clock-frequency = <25000000>; u-boot,dm-spl; }; + + mcu_conf: scm_conf@40f00000 { + compatible = "syscon", "simple-mfd"; + reg = <0x0 0x40f00000 0x0 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40f00000 0x20000>; + + phy_sel: cpsw-phy-sel@4040 { + compatible = "ti,am654-cpsw-phy-sel"; + reg = <0x4040 0x4>; + reg-names = "gmii-sel"; + }; + }; + + cbass_mcu_navss: mcu_navss { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + dma-ranges; + ranges; + + ti,sci-dev-id = <232>; + u-boot,dm-spl; + + mcu_ringacc: ringacc@2b800000 { + compatible = "ti,am654-navss-ringacc"; + reg = <0x0 0x2b800000 0x0 0x400000>, + <0x0 0x2b000000 0x0 0x400000>, + <0x0 0x28590000 0x0 0x100>, + <0x0 0x2a500000 0x0 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; + ti,num-rings = <286>; + ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ + ti,sci = <&dmsc>; + ti,sci-dev-id = <235>; + u-boot,dm-spl; + }; + + mcu_udmap: udmap@31150000 { + compatible = "ti,j721e-navss-mcu-udmap"; + reg = <0x0 0x285c0000 0x0 0x100>, + <0x0 0x2a800000 0x0 0x40000>, + <0x0 0x2aa00000 0x0 0x40000>; + reg-names = "gcfg", "rchanrt", "tchanrt"; + #dma-cells = <3>; + + ti,ringacc = <&mcu_ringacc>; + ti,psil-base = <0x6000>; + + ti,sci = <&dmsc>; + ti,sci-dev-id = <236>; + + ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ + <0x0f>; /* TX_HCHAN */ + ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ + <0x0b>; /* RX_HCHAN */ + ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + u-boot,dm-spl; + }; + }; + + mcu_cpsw: ethernet@046000000 { + compatible = "ti,j721e-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0x46000000 0x0 0x200000>; + reg-names = "cpsw_nuss"; + ranges; + dma-coherent; + clocks = <&k3_clks 18 22>; + clock-names = "fck"; + power-domains = <&k3_pds 18 TI_SCI_PD_EXCLUSIVE>; + ti,psil-base = <0x7000>; + cpsw-phy-sel = <&phy_sel>; + + dmas = <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 1 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 2 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 3 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 4 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 5 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 6 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 7 UDMA_DIR_TX>, + <&mcu_udmap &mcu_cpsw 0 UDMA_DIR_RX>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + host: host@0 { + reg = <0>; + ti,label = "host"; + }; + + cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + ti,label = "port1"; + ti,syscon-efuse = <&mcu_conf 0x200>; + }; + }; + + davinci_mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + bus_freq = <1000000>; + }; + + cpts { + clocks = <&k3_clks 18 2>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + + ti,psil-config0 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config1 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config2 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config3 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config4 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config5 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config6 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + + ti,psil-config7 { + linux,udma-mode = ; + statictr-type = ; + ti,needs-epib; + ti,psd-size = <16>; + }; + }; }; &secure_proxy_main { @@ -52,6 +237,29 @@ &wkup_pmx0 { u-boot,dm-spl; + mcu_cpsw_pins_default: mcu_cpsw_pins_default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0058, PIN_OUTPUT, 0) /* (N4) MCU_RGMII1_TX_CTL */ + J721E_WKUP_IOPAD(0x005c, PIN_INPUT, 0) /* (N5) MCU_RGMII1_RX_CTL */ + J721E_WKUP_IOPAD(0x0060, PIN_OUTPUT, 0) /* (M2) MCU_RGMII1_TD3 */ + J721E_WKUP_IOPAD(0x0064, PIN_OUTPUT, 0) /* (M3) MCU_RGMII1_TD2 */ + J721E_WKUP_IOPAD(0x0068, PIN_OUTPUT, 0) /* (M4) MCU_RGMII1_TD1 */ + J721E_WKUP_IOPAD(0x006c, PIN_OUTPUT, 0) /* (M5) MCU_RGMII1_TD0 */ + J721E_WKUP_IOPAD(0x0078, PIN_INPUT, 0) /* (L2) MCU_RGMII1_RD3 */ + J721E_WKUP_IOPAD(0x007c, PIN_INPUT, 0) /* (L5) MCU_RGMII1_RD2 */ + J721E_WKUP_IOPAD(0x0080, PIN_INPUT, 0) /* (M6) MCU_RGMII1_RD1 */ + J721E_WKUP_IOPAD(0x0084, PIN_INPUT, 0) /* (L6) MCU_RGMII1_RD0 */ + J721E_WKUP_IOPAD(0x0070, PIN_INPUT, 0) /* (N1) MCU_RGMII1_TXC */ + J721E_WKUP_IOPAD(0x0074, PIN_INPUT, 0) /* (M1) MCU_RGMII1_RXC */ + >; + }; + + mcu_mdio_pins_default: mcu_mdio1_pins_default { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x008c, PIN_OUTPUT, 0) /* (L1) MCU_MDIO0_MDC */ + J721E_WKUP_IOPAD(0x0088, PIN_INPUT, 0) /* (L4) MCU_MDIO0_MDIO */ + >; + }; }; &main_pmx0 { @@ -73,3 +281,33 @@ &main_sdhci1 { u-boot,dm-spl; }; + +&mcu_cpsw { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_pins_default &mcu_mdio_pins_default>; +}; + +&davinci_mdio { + phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; + +&cpsw_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&phy0>; +}; + +&mcu_cpsw { + reg = <0x0 0x46000000 0x0 0x200000>, + <0x0 0x40f00200 0x0 0x2>; + reg-names = "cpsw_nuss", "mac_efuse"; + + cpsw-phy-sel@40f04040 { + compatible = "ti,am654-cpsw-phy-sel"; + reg= <0x0 0x40f04040 0x0 0x4>; + reg-names = "gmii-sel"; + }; +}; From c627abe0de33622a962138b059f4054d3f9f032d Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 4 Dec 2019 22:17:25 +0530 Subject: [PATCH 59/60] configs: j721e_evm_a72_defconfig: Enable DMA and Ethernet Enable configs related to DMA and Ethernet so as to support networking at U-Boot prompt Signed-off-by: Vignesh Raghavendra Acked-by: Joe Hershberger Reviewed-by: Grygorii Strashko --- configs/j721e_evm_a72_defconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig index 61d28db803..daa661384d 100644 --- a/configs/j721e_evm_a72_defconfig +++ b/configs/j721e_evm_a72_defconfig @@ -51,6 +51,7 @@ CONFIG_DEFAULT_DEVICE_TREE="k3-j721e-common-proc-board" CONFIG_SPL_MULTI_DTB_FIT=y CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y @@ -61,6 +62,8 @@ CONFIG_SPL_OF_TRANSLATE=y CONFIG_CLK=y CONFIG_SPL_CLK=y CONFIG_CLK_TI_SCI=y +CONFIG_DMA_CHANNELS=y +CONFIG_TI_K3_NAVSS_UDMA=y CONFIG_TI_SCI_PROTOCOL=y CONFIG_DM_MAILBOX=y CONFIG_K3_SEC_PROXY=y @@ -79,6 +82,10 @@ CONFIG_SYS_FLASH_CFI=y CONFIG_HBMC_AM654=y CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_STMICRO=y +CONFIG_PHY_TI=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_TI_AM65_CPSW_NUSS=y CONFIG_PINCTRL=y # CONFIG_PINCTRL_GENERIC is not set CONFIG_SPL_PINCTRL=y @@ -93,6 +100,7 @@ CONFIG_RESET_TI_SCI=y CONFIG_SCSI=y CONFIG_DM_SCSI=y CONFIG_DM_SERIAL=y +CONFIG_SOC_TI=y CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_CADENCE_QSPI=y From 2c4e067d493d031d1267eea1c635d1eab93ce8f7 Mon Sep 17 00:00:00 2001 From: Ben Wolsieffer Date: Thu, 28 Nov 2019 00:07:08 -0500 Subject: [PATCH 60/60] cmd: pxe: Increase maximum path length On NixOS, cross compiled kernels have long suffixes that cause them to exceed the current maximum path length. The PXE/TFTP max path length is used for extlinux.conf support as well, which is where this problem usually manifest's itself. Signed-off-by: Ben Wolsieffer Acked-by: Joe Hershberger --- cmd/pxe_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/pxe_utils.c b/cmd/pxe_utils.c index 42b584ead3..a636346bb5 100644 --- a/cmd/pxe_utils.c +++ b/cmd/pxe_utils.c @@ -22,7 +22,7 @@ #include "pxe_utils.h" -#define MAX_TFTP_PATH_LEN 127 +#define MAX_TFTP_PATH_LEN 512 bool is_pxe;