From 5e6e41b3bab32f2ee258a76fda68b703e8f10cc3 Mon Sep 17 00:00:00 2001 From: Andre Kalb Date: Fri, 28 Jan 2022 09:40:32 +0100 Subject: [PATCH 01/17] net: bootp: Make root path (option 17) length configurable to adjust the root path length. Eg to 256 from Linux Kernel Signed-off-by: Andre Kalb Reviewed-by: Ramon Fried [trini: Guard extern so that !CONFIG_NET platforms will build] Signed-off-by: Tom Rini --- include/net.h | 4 +++- net/Kconfig | 6 ++++++ net/bootp.c | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/net.h b/include/net.h index e3889a0bc85..c06b577808b 100644 --- a/include/net.h +++ b/include/net.h @@ -536,7 +536,9 @@ extern struct in_addr net_dns_server2; #endif extern char net_nis_domain[32]; /* Our IS domain */ extern char net_hostname[32]; /* Our hostname */ -extern char net_root_path[64]; /* Our root path */ +#ifdef CONFIG_NET +extern char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN]; /* Our root path */ +#endif /** END OF BOOTP EXTENTIONS **/ extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ diff --git a/net/Kconfig b/net/Kconfig index 564ea8b2d28..52e261884d1 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -168,6 +168,12 @@ config BOOTP_SERVERIP variable, not the BOOTP server. This affects the operation of both bootp and tftp. +config BOOTP_MAX_ROOT_PATH_LEN + int "Option 17 root path length" + default 64 + help + Select maximal length of option 17 root path. + endif # if NET config SYS_RX_ETH_BUFFER diff --git a/net/bootp.c b/net/bootp.c index a544bfcc234..b260d5d09e6 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -59,7 +59,7 @@ ulong bootp_start; ulong bootp_timeout; char net_nis_domain[32] = {0,}; /* Our NIS domain */ char net_hostname[32] = {0,}; /* Our hostname */ -char net_root_path[64] = {0,}; /* Our bootpath */ +char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */ static ulong time_taken_max; From 0ef02619ef01ad7e33805e9f9213cd289e2da0fc Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 31 Mar 2022 11:43:06 +0200 Subject: [PATCH 02/17] net: phy: marvell: Support reg config via "marvell, reg-init" DT property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the "marvell,reg-init" DT property, which is used to describe board specific Marvell PHY register configurations in the board dts file. This DT property is supported in the Linux Kernel since a longer time. Adding it to U-Boot now, enables the boards which describe the register settings in their DT files here as well. I've included calling this marvell_of_reg_init() to all foo_config() functions in this patch as well. If CONFIG_DM_ETH is not set, there is no ofnode, or no "marvell,reg-init" property, the PHY initialization is unchanged. The function marvell_of_reg_init() is a port of the Linux version. Please note that I explicitly did not add error checking and handling to the U-Boot version, as this is basically not done for phy_read/write in this Marvell PHY code. This will be used by the upcoming ethernet support on the MIPS Octeon EBB 7304 board. Signed-off-by: Stefan Roese Cc: Ramon Fried Cc: Joe Hershberger Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Marek Behún Reviewed-by: Marek Behún --- drivers/net/phy/marvell.c | 100 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index a62c695c5c8..1dcb79db242 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -104,6 +104,88 @@ #define MIIM_88E151x_MODE_SGMII 1 #define MIIM_88E151x_RESET_OFFS 15 +#if IS_ENABLED(CONFIG_DM_ETH) +static int marvell_read_page(struct phy_device *phydev) +{ + return phy_read(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE); +} + +static int marvell_write_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MDIO_DEVAD_NONE, MII_MARVELL_PHY_PAGE, page); +} + +/* Set and/or override some configuration registers based on the + * marvell,reg-init property stored in the of_node for the phydev. + * + * marvell,reg-init = ,...; + * + * There may be one or more sets of : + * + * reg-page: which register bank to use. + * reg: the register. + * mask: if non-zero, ANDed with existing register value. + * value: ORed with the masked value and written to the regiser. + * + */ +static int marvell_of_reg_init(struct phy_device *phydev) +{ + const __be32 *prop; + int len, i, saved_page, current_page, ret = 0; + + if (!ofnode_valid(phydev->node)) + return 0; + + prop = ofnode_get_property(phydev->node, "marvell,reg-init", &len); + if (!prop) + return 0; + + saved_page = marvell_read_page(phydev); + if (saved_page < 0) + goto err; + current_page = saved_page; + + len /= sizeof(*prop); + for (i = 0; i < len - 3; i += 4) { + u16 page = be32_to_cpup(prop + i); + u16 reg = be32_to_cpup(prop + i + 1); + u16 mask = be32_to_cpup(prop + i + 2); + u16 val_bits = be32_to_cpup(prop + i + 3); + int val; + + if (page != current_page) { + current_page = page; + ret = marvell_write_page(phydev, page); + if (ret < 0) + goto err; + } + + val = 0; + if (mask) { + val = phy_read(phydev, MDIO_DEVAD_NONE, reg); + if (val < 0) { + ret = val; + goto err; + } + val &= mask; + } + val |= val_bits; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, reg, val); + if (ret < 0) + goto err; + } + +err: + return marvell_write_page(phydev, saved_page); +} +#else +static int marvell_of_reg_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_DM_ETH */ + static int m88e1xxx_phy_extread(struct phy_device *phydev, int addr, int devaddr, int regnum) { @@ -143,6 +225,8 @@ static int m88e1011s_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + marvell_of_reg_init(phydev); + genphy_config_aneg(phydev); return 0; @@ -298,6 +382,8 @@ static int m88e1111s_config(struct phy_device *phydev) /* soft reset */ phy_reset(phydev); + marvell_of_reg_init(phydev); + genphy_config_aneg(phydev); genphy_restart_aneg(phydev); @@ -397,6 +483,8 @@ static int m88e151x_config(struct phy_device *phydev) /* soft reset */ phy_reset(phydev); + marvell_of_reg_init(phydev); + genphy_config_aneg(phydev); genphy_restart_aneg(phydev); @@ -417,6 +505,8 @@ static int m88e1118_config(struct phy_device *phydev) /* Change Page Number */ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + marvell_of_reg_init(phydev); + return genphy_config_aneg(phydev); } @@ -439,6 +529,8 @@ static int m88e1121_config(struct phy_device *phydev) { int pg; + marvell_of_reg_init(phydev); + /* Configure the PHY */ genphy_config_aneg(phydev); @@ -479,6 +571,8 @@ static int m88e1145_config(struct phy_device *phydev) MIIM_M88E1145_RGMII_TX_DELAY; phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); + marvell_of_reg_init(phydev); + genphy_config_aneg(phydev); /* soft reset */ @@ -511,6 +605,8 @@ static int m88e1149_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + marvell_of_reg_init(phydev); + genphy_config_aneg(phydev); phy_reset(phydev); @@ -544,6 +640,8 @@ static int m88e1310_config(struct phy_device *phydev) /* Ensure to return to page 0 */ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); + marvell_of_reg_init(phydev); + return genphy_config_aneg(phydev); } @@ -578,6 +676,8 @@ static int m88e1680_config(struct phy_device *phydev) phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); phy_write(phydev, MDIO_DEVAD_NONE, 0, 0x9140); + marvell_of_reg_init(phydev); + res = genphy_config_aneg(phydev); if (res < 0) return res; From 01207947d54e4d8a356a19658640213be4939f62 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 31 Mar 2022 11:43:07 +0200 Subject: [PATCH 03/17] net: phy: marvell: Add support for 88E1240 PHY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds basic support for the Marvell 88E1240 PHY. This will be used by the upcoming ethernet support addition for the Marvell MIPS Octeon EBB7304 platform. Signed-off-by: Stefan Roese Cc: Ramon Fried Cc: Joe Hershberger Cc: Aaron Williams Cc: Chandrakala Chavva Reviewed-by: Marek Behún --- drivers/net/phy/marvell.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 1dcb79db242..212a861596f 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -614,6 +614,16 @@ static int m88e1149_config(struct phy_device *phydev) return 0; } +/* Marvell 88E1240 */ +static int m88e1240_config(struct phy_device *phydev) +{ + marvell_of_reg_init(phydev); + + genphy_config_aneg(phydev); + + return 0; +} + /* Marvell 88E1310 */ static int m88e1310_config(struct phy_device *phydev) { @@ -760,6 +770,16 @@ static struct phy_driver M88E1149S_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1240_driver = { + .name = "Marvell 88E1240", + .uid = 0x1410e30, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1240_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + static struct phy_driver M88E151x_driver = { .name = "Marvell 88E151x", .uid = 0x1410dd0, @@ -802,6 +822,7 @@ int phy_marvell_init(void) phy_register(&M88E1118R_driver); phy_register(&M88E1111S_driver); phy_register(&M88E1011S_driver); + phy_register(&M88E1240_driver); phy_register(&M88E151x_driver); phy_register(&M88E1680_driver); From ecd8b0371386eb0b1826f5d067a3086ad5184a85 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Apr 2022 20:28:05 +0200 Subject: [PATCH 04/17] net: dm9000: Correctly handle empty FIFO Assign packet pointer only in case the MAC reports anything in the FIFO. In case the MAC indicates empty FIFO, return 0 to pass that information to the network stack. Signed-off-by: Marek Vasut Cc: Joe Hershberger Cc: Ramon Fried Reviewed-by: Ramon Fried --- drivers/net/dm9000x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index 78ce536d4a3..07733df533e 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -666,10 +666,10 @@ static int dm9000_recv(struct udevice *dev, int flags, uchar **packetp) int ret; ret = dm9000_recv_common(db, data); - if (ret) + if (ret > 0) *packetp = (void *)data; - return ret ? ret : -EAGAIN; + return ret >= 0 ? ret : -EAGAIN; } static int dm9000_write_hwaddr(struct udevice *dev) From 4a7c9dbf9a42330970a9742c1d476f2a9075f3f9 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 11 May 2022 16:12:50 +0200 Subject: [PATCH 05/17] net: dwc_eth_qos: fix double resource leak in eqos_remove() Not only does eqos_remove() fail to free the buffers that have been allocated by eqos_probe_resources_core(), it repeats those allocations and thus drops twice as much memory on the floor. Signed-off-by: Rasmus Villemoes Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index c1f2391d635..7c504dd1ca5 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1574,7 +1574,7 @@ static int eqos_remove(struct udevice *dev) eqos->config->ops->eqos_stop_clks(dev); eqos->config->ops->eqos_remove_resources(dev); - eqos_probe_resources_core(dev); + eqos_remove_resources_core(dev); debug("%s: OK\n", __func__); return 0; From 0c999ce98e9d6485f8637e130f7612f80c111a0e Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 11 May 2022 16:58:41 +0200 Subject: [PATCH 06/17] net: dwc_eth_qos: lift parsing of max-speed DT property to common code I have an iMX8MP with a ti,dp83867 phy in front of the eqos interface. The phy is Gbit capable - however, the C and D differential pairs are not physically routed to the RJ45 connector. So I need to prevent the phy from advertising 1000Mbps. The necessary code is almost already there in the form of a phy_set_supported() call in eqos_start(), but the max-speed DT property is currently only parsed in eqos_probe_resources_stm32(). Lift that parsing to eqos_probe(). Signed-off-by: Rasmus Villemoes Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 7c504dd1ca5..4f3ea4f6295 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1399,8 +1399,6 @@ static int eqos_probe_resources_stm32(struct udevice *dev) if (ret) return -EINVAL; - eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); - ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); if (ret) { pr_err("clk_get_by_name(master_bus) failed: %d", ret); @@ -1503,6 +1501,8 @@ static int eqos_probe(struct udevice *dev) eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE); eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE); + eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); + ret = eqos_probe_resources_core(dev); if (ret < 0) { pr_err("eqos_probe_resources_core() failed: %d", ret); From c62b74652a330b09e2157b6ebc1f4d9ea3cec254 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 12 May 2022 09:33:07 +0200 Subject: [PATCH 07/17] net: dwc_eth_qos: remove use of DWC_NET_PHYADDR Only two boards in the tree set the macro DWC_NET_PHYADDR. Both have CONFIG_DM_ETH_PHY=y, so should set the phy address in DT if necessary. The imx8mp_evk does set the correct address in device tree. The other board seems to be a copy-paste-adapt from an old version of the imx8mp_evk config header, given the "#ifdef CONFIG_DWC_ETH_QOS" block that has been removed from imx8mp_evk header in commit 127fb454955. Its device tree doesn't even enable (i.e., set 'status = "okay"') the &eqos node. But the other ethernet device, &fec, does get enabled, and does have a phy sitting at address 4 (and it also has a corresponding legacy #define CONFIG_FEC_MXC_PHYADDR 4). So I believe it should be completely safe to remove it from there as well. Signed-off-by: Rasmus Villemoes Reviewed-by: Ramon Fried [trini: Re-apply to top of tree, update imx93_evk.h] Signed-off-by: Tom Rini --- drivers/net/dwc_eth_qos.c | 3 --- include/configs/imx8mp_evk.h | 2 -- include/configs/imx8mp_rsb3720.h | 1 - include/configs/imx93_evk.h | 1 - 4 files changed, 7 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 4f3ea4f6295..43af7d91f81 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -789,9 +789,6 @@ static int eqos_start(struct udevice *dev) if (!eqos->phy) { int addr = -1; addr = eqos_get_phy_addr(eqos, dev); -#ifdef DWC_NET_PHYADDR - addr = DWC_NET_PHYADDR; -#endif eqos->phy = phy_connect(eqos->mii, addr, dev, eqos->config->interface(dev)); if (!eqos->phy) { diff --git a/include/configs/imx8mp_evk.h b/include/configs/imx8mp_evk.h index 5581c0fac02..388f3bc9ffe 100644 --- a/include/configs/imx8mp_evk.h +++ b/include/configs/imx8mp_evk.h @@ -24,8 +24,6 @@ #if defined(CONFIG_CMD_NET) #define CONFIG_FEC_MXC_PHYADDR 1 -#define DWC_NET_PHYADDR 1 - #define PHY_ANEG_TIMEOUT 20000 #endif diff --git a/include/configs/imx8mp_rsb3720.h b/include/configs/imx8mp_rsb3720.h index 17e00f958b6..ddc035ae228 100644 --- a/include/configs/imx8mp_rsb3720.h +++ b/include/configs/imx8mp_rsb3720.h @@ -42,7 +42,6 @@ #if defined(CONFIG_CMD_NET) #define CONFIG_FEC_MXC_PHYADDR 4 -#define DWC_NET_PHYADDR 4 #ifdef CONFIG_DWC_ETH_QOS #define CONFIG_SYS_NONCACHED_MEMORY (1 * SZ_1M) /* 1M */ #endif diff --git a/include/configs/imx93_evk.h b/include/configs/imx93_evk.h index 21f85f59b28..f9750da5805 100644 --- a/include/configs/imx93_evk.h +++ b/include/configs/imx93_evk.h @@ -138,7 +138,6 @@ #define WDOG_BASE_ADDR WDG3_BASE_ADDR #if defined(CONFIG_CMD_NET) -#define DWC_NET_PHYADDR 1 #define PHY_ANEG_TIMEOUT 20000 #endif From 81844aced3105af39d60efa3aed1ced9dc14f6e3 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 12 May 2022 15:48:51 +0200 Subject: [PATCH 08/17] net: mpc8xx_fec: Migrate to DM_ETH Migrate mpc8xx_fec driver to DM_ETH. Signed-off-by: Christophe Leroy Reviewed-by: Ramon Fried --- arch/powerpc/cpu/mpc8xx/cpu.c | 12 --- arch/powerpc/dts/mcr3000.dts | 4 + configs/MCR3000_defconfig | 1 + drivers/net/Kconfig | 1 + drivers/net/mpc8xx_fec.c | 187 ++++++++++++++++++---------------- include/netdev.h | 1 - 6 files changed, 103 insertions(+), 103 deletions(-) diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c index 6d16ed084e6..0ccb9f6df6f 100644 --- a/arch/powerpc/cpu/mpc8xx/cpu.c +++ b/arch/powerpc/cpu/mpc8xx/cpu.c @@ -266,15 +266,3 @@ unsigned long get_tbclk(void) return oscclk / 16; } - -/* - * Initializes on-chip ethernet controllers. - * to override, implement board_eth_init() - */ -int cpu_eth_init(struct bd_info *bis) -{ -#if defined(CONFIG_MPC8XX_FEC) - fec_initialize(bis); -#endif - return 0; -} diff --git a/arch/powerpc/dts/mcr3000.dts b/arch/powerpc/dts/mcr3000.dts index 5abf111dc5f..5f32d8a2e55 100644 --- a/arch/powerpc/dts/mcr3000.dts +++ b/arch/powerpc/dts/mcr3000.dts @@ -16,6 +16,10 @@ compatible = "fsl,pq1-smc"; }; + FEC: fec@0 { + compatible = "fsl,pq1-fec1"; + }; + chosen { stdout-path = &SERIAL; }; diff --git a/configs/MCR3000_defconfig b/configs/MCR3000_defconfig index 086507e6016..94743d69d12 100644 --- a/configs/MCR3000_defconfig +++ b/configs/MCR3000_defconfig @@ -91,3 +91,4 @@ CONFIG_DM_SERIAL=y CONFIG_WDT=y CONFIG_SHA256=y CONFIG_LZMA=y +CONFIG_DM_ETH=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 93e7dbe9766..0070ff73eaf 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -744,6 +744,7 @@ config RENESAS_RAVB config MPC8XX_FEC bool "Fast Ethernet Controller on MPC8XX" depends on MPC8xx + depends on DM_ETH select MII select SYS_DISCOVER_PHY help diff --git a/drivers/net/mpc8xx_fec.c b/drivers/net/mpc8xx_fec.c index 4eb82602811..78337731e1f 100644 --- a/drivers/net/mpc8xx_fec.c +++ b/drivers/net/mpc8xx_fec.c @@ -41,7 +41,7 @@ DECLARE_GLOBAL_DATA_PTR; #endif #ifdef CONFIG_SYS_DISCOVER_PHY -static int mii_discover_phy(struct eth_device *dev); +static int mii_discover_phy(struct udevice *dev); #endif int fec8xx_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg); @@ -111,50 +111,24 @@ struct common_buf_desc { static struct common_buf_desc __iomem *rtx; -static int fec_send(struct eth_device *dev, void *packet, int length); -static int fec_recv(struct eth_device *dev); -static int fec_init(struct eth_device *dev, struct bd_info *bd); -static void fec_halt(struct eth_device *dev); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) static void __mii_init(void); #endif -int fec_initialize(struct bd_info *bis) +static int fec_probe(struct udevice *dev) { - struct eth_device *dev; - struct ether_fcc_info_s *efis; + struct ether_fcc_info_s *efis = dev_get_priv(dev); + int index = dev_get_driver_data(dev); int i; for (i = 0; i < ARRAY_SIZE(ether_fcc_info); i++) { - dev = malloc(sizeof(*dev)); - if (dev == NULL) - hang(); + if (ether_fcc_info[i].ether_index != index) + continue; - memset(dev, 0, sizeof(*dev)); + memcpy(efis, ðer_fcc_info[i], sizeof(*efis)); - /* for FEC1 make sure that the name of the interface is the same - as the old one for compatibility reasons */ - if (i == 0) - strcpy(dev->name, "FEC"); - else - sprintf(dev->name, "FEC%d", - ether_fcc_info[i].ether_index + 1); - - efis = ðer_fcc_info[i]; - - /* - * reset actual phy addr - */ efis->actual_phy_addr = -1; - dev->priv = efis; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; - - eth_register(dev); - #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) int retval; struct mii_dev *mdiodev = mdio_alloc(); @@ -169,13 +143,13 @@ int fec_initialize(struct bd_info *bis) return retval; #endif } - return 1; + return 0; } -static int fec_send(struct eth_device *dev, void *packet, int length) +static int fec_send(struct udevice *dev, void *packet, int length) { int j, rc; - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); fec_t __iomem *fecp = (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); @@ -217,59 +191,57 @@ static int fec_send(struct eth_device *dev, void *packet, int length) return rc; } -static int fec_recv(struct eth_device *dev) +static int fec_recv(struct udevice *dev, int flags, uchar **packetp) { - struct ether_fcc_info_s *efis = dev->priv; - fec_t __iomem *fecp = - (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); int length; - for (;;) { - /* section 16.9.23.2 */ - if (in_be16(&rtx->rxbd[rxIdx].cbd_sc) & BD_ENET_RX_EMPTY) { - length = -1; - break; /* nothing received - leave for() loop */ - } + /* section 16.9.23.2 */ + if (in_be16(&rtx->rxbd[rxIdx].cbd_sc) & BD_ENET_RX_EMPTY) + return -EAGAIN; - length = in_be16(&rtx->rxbd[rxIdx].cbd_datlen); + length = in_be16(&rtx->rxbd[rxIdx].cbd_datlen); - if (!(in_be16(&rtx->rxbd[rxIdx].cbd_sc) & 0x003f)) { - uchar *rx = net_rx_packets[rxIdx]; - - length -= 4; + if (!(in_be16(&rtx->rxbd[rxIdx].cbd_sc) & 0x003f)) { + uchar *rx = net_rx_packets[rxIdx]; #if defined(CONFIG_CMD_CDP) - if ((rx[0] & 1) != 0 && - memcmp((uchar *)rx, net_bcast_ethaddr, 6) != 0 && - !is_cdp_packet((uchar *)rx)) - rx = NULL; + if ((rx[0] & 1) != 0 && + memcmp((uchar *)rx, net_bcast_ethaddr, 6) != 0 && + !is_cdp_packet((uchar *)rx)) + return 0; #endif - /* - * Pass the packet up to the protocol layers. - */ - if (rx != NULL) - net_process_received_packet(rx, length); - } + *packetp = rx; - /* Give the buffer back to the FEC. */ - out_be16(&rtx->rxbd[rxIdx].cbd_datlen, 0); + return length - 4; + } else { + return 0; + } +} - /* wrap around buffer index when necessary */ - if ((rxIdx + 1) >= PKTBUFSRX) { - out_be16(&rtx->rxbd[PKTBUFSRX - 1].cbd_sc, - BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); - rxIdx = 0; - } else { - out_be16(&rtx->rxbd[rxIdx].cbd_sc, BD_ENET_RX_EMPTY); - rxIdx++; - } +static int fec_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct ether_fcc_info_s *efis = dev_get_priv(dev); + fec_t __iomem *fecp = + (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); - /* Try to fill Buffer Descriptors */ - /* Descriptor polling active */ - out_be32(&fecp->fec_r_des_active, 0x01000000); + /* Give the buffer back to the FEC. */ + out_be16(&rtx->rxbd[rxIdx].cbd_datlen, 0); + + /* wrap around buffer index when necessary */ + if ((rxIdx + 1) >= PKTBUFSRX) { + out_be16(&rtx->rxbd[PKTBUFSRX - 1].cbd_sc, + BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + rxIdx = 0; + } else { + out_be16(&rtx->rxbd[rxIdx].cbd_sc, BD_ENET_RX_EMPTY); + rxIdx++; } - return length; + /* Try to fill Buffer Descriptors */ + /* Descriptor polling active */ + out_be32(&fecp->fec_r_des_active, 0x01000000); + + return 0; } /************************************************************** @@ -296,9 +268,9 @@ static int fec_recv(struct eth_device *dev) #if defined(CONFIG_RMII) -static inline void fec_10Mbps(struct eth_device *dev) +static inline void fec_10Mbps(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); int fecidx = efis->ether_index; uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; @@ -309,9 +281,9 @@ static inline void fec_10Mbps(struct eth_device *dev) setbits_be32(&immr->im_cpm.cp_cptr, mask); } -static inline void fec_100Mbps(struct eth_device *dev) +static inline void fec_100Mbps(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); int fecidx = efis->ether_index; uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; @@ -324,9 +296,9 @@ static inline void fec_100Mbps(struct eth_device *dev) #endif -static inline void fec_full_duplex(struct eth_device *dev) +static inline void fec_full_duplex(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); fec_t __iomem *fecp = (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); @@ -334,9 +306,9 @@ static inline void fec_full_duplex(struct eth_device *dev) setbits_be32(&fecp->fec_x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ } -static inline void fec_half_duplex(struct eth_device *dev) +static inline void fec_half_duplex(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); fec_t __iomem *fecp = (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); @@ -497,9 +469,10 @@ static int fec_reset(fec_t __iomem *fecp) return 0; } -static int fec_init(struct eth_device *dev, struct bd_info *bd) +static int fec_start(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct eth_pdata *plat = dev_get_plat(dev); + struct ether_fcc_info_s *efis = dev_get_priv(dev); immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; fec_t __iomem *fecp = (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); @@ -529,7 +502,7 @@ static int fec_init(struct eth_device *dev, struct bd_info *bd) /* Set station address */ -#define ea dev->enetaddr +#define ea plat->enetaddr out_be32(&fecp->fec_addr_low, (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | ea[3]); out_be16(&fecp->fec_addr_high, (ea[4] << 8) | ea[5]); @@ -665,9 +638,9 @@ static int fec_init(struct eth_device *dev, struct bd_info *bd) } -static void fec_halt(struct eth_device *dev) +static void fec_stop(struct udevice *dev) { - struct ether_fcc_info_s *efis = dev->priv; + struct ether_fcc_info_s *efis = dev_get_priv(dev); fec_t __iomem *fecp = (fec_t __iomem *)(CONFIG_SYS_IMMR + efis->fecp_offset); int i; @@ -750,7 +723,7 @@ mii_send(uint mii_cmd) #endif #if defined(CONFIG_SYS_DISCOVER_PHY) -static int mii_discover_phy(struct eth_device *dev) +static int mii_discover_phy(struct udevice *dev) { #define MAX_PHY_PASSES 11 uint phyno; @@ -854,3 +827,37 @@ int fec8xx_miiphy_write(struct mii_dev *bus, int addr, int devad, int reg, return 0; } #endif + +static const struct eth_ops fec_ops = { + .start = fec_start, + .send = fec_send, + .recv = fec_recv, + .stop = fec_stop, + .free_pkt = fec_free_pkt, +}; + +static const struct udevice_id fec_ids[] = { +#ifdef CONFIG_ETHER_ON_FEC1 + { + .compatible = "fsl,pq1-fec1", + .data = 0, + }, +#endif +#ifdef CONFIG_ETHER_ON_FEC2 + { + .compatible = "fsl,pq1-fec2", + .data = 1, + }, +#endif + { } +}; + +U_BOOT_DRIVER(fec) = { + .name = "fec", + .id = UCLASS_ETH, + .of_match = fec_ids, + .probe = fec_probe, + .ops = &fec_ops, + .priv_auto = sizeof(struct ether_fcc_info_s), + .plat_auto = sizeof(struct eth_pdata), +}; diff --git a/include/netdev.h b/include/netdev.h index fb18f09893c..b3f8584e900 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -42,7 +42,6 @@ int eepro100_initialize(struct bd_info *bis); int ep93xx_eth_initialize(u8 dev_num, int base_addr); int eth_3com_initialize (struct bd_info * bis); int ethoc_initialize(u8 dev_num, int base_addr); -int fec_initialize (struct bd_info *bis); int fecmxc_initialize(struct bd_info *bis); int fecmxc_initialize_multi(struct bd_info *bis, int dev_id, int phy_id, uint32_t addr); From 52503d813578e1d74b8dbac134f06c52929c7df8 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 17 May 2022 16:28:11 +0800 Subject: [PATCH 09/17] net: nuvoton : Add NPCM7xx EMAC driver NPCM750 provides identical ethernet MAC controllers for WAN/LAN applications. Signed-off-by: Jim Liu Reviewed-by: Ramon Fried --- drivers/net/Kconfig | 5 + drivers/net/Makefile | 1 + drivers/net/npcm750_eth.c | 745 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 751 insertions(+) create mode 100644 drivers/net/npcm750_eth.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0070ff73eaf..52dc9e4f0f6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -523,6 +523,11 @@ config MT7628_ETH The MediaTek MT7628 ethernet interface is used on MT7628 and MT7688 based boards. +config NET_NPCM750 + bool "Nuvoton NPCM750 Ethernet MAC" + help + support NPCM750 EMAC + config NET_OCTEON bool "MIPS Octeon ethernet support" depends on ARCH_OCTEON diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9536af11946..054ec68470d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_MVMDIO) += mvmdio.o obj-$(CONFIG_MVNETA) += mvneta.o obj-$(CONFIG_MVPP2) += mvpp2.o obj-$(CONFIG_NETCONSOLE) += netconsole.o +obj-$(CONFIG_NET_NPCM750) += npcm750_eth.o obj-$(CONFIG_NET_OCTEON) += octeon/ obj-$(CONFIG_NET_OCTEONTX) += octeontx/ obj-$(CONFIG_NET_OCTEONTX2) += octeontx2/ diff --git a/drivers/net/npcm750_eth.c b/drivers/net/npcm750_eth.c new file mode 100644 index 00000000000..409d5cce4a7 --- /dev/null +++ b/drivers/net/npcm750_eth.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAC_ADDR_SIZE 6 +#define CONFIG_TX_DESCR_NUM 32 +#define CONFIG_RX_DESCR_NUM 32 + +#define TX_TOTAL_BUFSIZE \ + ((CONFIG_TX_DESCR_NUM + 1) * PKTSIZE_ALIGN + PKTALIGN) +#define RX_TOTAL_BUFSIZE \ + ((CONFIG_RX_DESCR_NUM + 1) * PKTSIZE_ALIGN + PKTALIGN) + +#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ) + +struct npcm750_rxbd { + unsigned int sl; + unsigned int buffer; + unsigned int reserved; + unsigned int next; +} __aligned(ARCH_DMA_MINALIGN); + +struct npcm750_txbd { + unsigned int mode; + unsigned int buffer; + unsigned int sl; + unsigned int next; +} __aligned(ARCH_DMA_MINALIGN); + +struct emc_regs { + u32 camcmr; /* 0x00 */ + u32 camen; /* 0x04 */ + u32 cam0m; /* 0x08 */ + u32 cam0l; /* 0x0c */ + u32 cam1m; /* 0x10 */ + u32 cam1l; /* 0x14 */ + u32 cam2m; /* 0x18 */ + u32 cam2l; /* 0x1c */ + u32 cam3m; /* 0x20 */ + u32 cam3l; /* 0x24 */ + u32 cam4m; /* 0x28 */ + u32 cam4l; /* 0x2c */ + u32 cam5m; /* 0x30 */ + u32 cam5l; /* 0x34 */ + u32 cam6m; /* 0x38 */ + u32 cam6l; /* 0x3c */ + u32 cam7m; /* 0x40 */ + u32 cam7l; /* 0x44 */ + u32 cam8m; /* 0x48 */ + u32 cam8l; /* 0x4c */ + u32 cam9m; /* 0x50 */ + u32 cam9l; /* 0x54 */ + u32 cam10m; /* 0x58 */ + u32 cam10l; /* 0x5c */ + u32 cam11m; /* 0x60 */ + u32 cam11l; /* 0x64 */ + u32 cam12m; /* 0x68 */ + u32 cam12l; /* 0x6c */ + u32 cam13m; /* 0x70 */ + u32 cam13l; /* 0x74 */ + u32 cam14m; /* 0x78 */ + u32 cam14l; /* 0x7c */ + u32 cam15m; /* 0x80 */ + u32 cam15l; /* 0x84 */ + u32 txdlsa; /* 0x88 */ + u32 rxdlsa; /* 0x8c */ + u32 mcmdr; /* 0x90 */ + u32 miid; /* 0x94 */ + u32 miida; /* 0x98 */ + u32 fftcr; /* 0x9c */ + u32 tsdr; /* 0xa0 */ + u32 rsdr; /* 0xa4 */ + u32 dmarfc; /* 0xa8 */ + u32 mien; /* 0xac */ + u32 mista; /* 0xb0 */ + u32 mgsta; /* 0xb4 */ + u32 mpcnt; /* 0xb8 */ + u32 mrpc; /* 0xbc */ + u32 mrpcc; /* 0xc0 */ + u32 mrepc; /* 0xc4 */ + u32 dmarfs; /* 0xc8 */ + u32 ctxdsa; /* 0xcc */ + u32 ctxbsa; /* 0xd0 */ + u32 crxdsa; /* 0xd4 */ + u32 crxbsa; /* 0xd8 */ +}; + +struct npcm750_eth_dev { + struct npcm750_txbd tdesc[CONFIG_TX_DESCR_NUM] __aligned(ARCH_DMA_MINALIGN); + struct npcm750_rxbd rdesc[CONFIG_RX_DESCR_NUM] __aligned(ARCH_DMA_MINALIGN); + u8 txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN); + u8 rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN); + struct emc_regs *emc_regs_p; + struct phy_device *phydev; + struct mii_dev *bus; + struct npcm750_txbd *curr_txd; + struct npcm750_rxbd *curr_rxd; + u32 interface; + u32 max_speed; + u32 idx; + struct regmap *gcr_regmap; +}; + +struct npcm750_eth_pdata { + struct eth_pdata eth_pdata; +}; + +/* mac controller bit */ +#define MCMDR_RXON BIT(0) +#define MCMDR_ACP BIT(3) +#define MCMDR_SPCRC BIT(5) +#define MCMDR_TXON BIT(8) +#define MCMDR_NDEF BIT(9) +#define MCMDR_FDUP BIT(18) +#define MCMDR_ENMDC BIT(19) +#define MCMDR_OPMOD BIT(20) +#define MCMDR_SWR BIT(24) + +/* cam command regiser */ +#define CAMCMR_AUP 0x01 +#define CAMCMR_AMP BIT(1) +#define CAMCMR_ABP BIT(2) +#define CAMCMR_CCAM BIT(3) +#define CAMCMR_ECMP BIT(4) +#define CAM0EN 0x01 + +/* mac mii controller bit */ +#define MDCON BIT(19) +#define PHYAD BIT(8) +#define PHYWR BIT(16) +#define PHYBUSY BIT(17) +#define PHYPRESP BIT(18) +#define CAM_ENTRY_SIZE 0x08 + +/* rx and tx status */ +#define TXDS_TXCP BIT(19) +#define RXDS_CRCE BIT(17) +#define RXDS_PTLE BIT(19) +#define RXDS_RXGD BIT(20) +#define RXDS_ALIE BIT(21) +#define RXDS_RP BIT(22) + +/* mac interrupt status*/ +#define MISTA_RXINTR BIT(0) +#define MISTA_CRCE BIT(1) +#define MISTA_RXOV BIT(2) +#define MISTA_PTLE BIT(3) +#define MISTA_RXGD BIT(4) +#define MISTA_ALIE BIT(5) +#define MISTA_RP BIT(6) +#define MISTA_MMP BIT(7) +#define MISTA_DFOI BIT(8) +#define MISTA_DENI BIT(9) +#define MISTA_RDU BIT(10) +#define MISTA_RXBERR BIT(11) +#define MISTA_CFR BIT(14) +#define MISTA_TXINTR BIT(16) +#define MISTA_TXEMP BIT(17) +#define MISTA_TXCP BIT(18) +#define MISTA_EXDEF BIT(19) +#define MISTA_NCS BIT(20) +#define MISTA_TXABT BIT(21) +#define MISTA_LC BIT(22) +#define MISTA_TDU BIT(23) +#define MISTA_TXBERR BIT(24) + +#define ENSTART 0x01 +#define ENRXINTR BIT(0) +#define ENCRCE BIT(1) +#define EMRXOV BIT(2) +#define ENPTLE BIT(3) +#define ENRXGD BIT(4) +#define ENALIE BIT(5) +#define ENRP BIT(6) +#define ENMMP BIT(7) +#define ENDFO BIT(8) +#define ENDENI BIT(9) +#define ENRDU BIT(10) +#define ENRXBERR BIT(11) +#define ENCFR BIT(14) +#define ENTXINTR BIT(16) +#define ENTXEMP BIT(17) +#define ENTXCP BIT(18) +#define ENTXDEF BIT(19) +#define ENNCS BIT(20) +#define ENTXABT BIT(21) +#define ENLC BIT(22) +#define ENTDU BIT(23) +#define ENTXBERR BIT(24) + +#define RX_STAT_RBC 0xffff +#define RX_STAT_RXINTR BIT(16) +#define RX_STAT_CRCE BIT(17) +#define RX_STAT_PTLE BIT(19) +#define RX_STAT_RXGD BIT(20) +#define RX_STAT_ALIE BIT(21) +#define RX_STAT_RP BIT(22) +#define RX_STAT_OWNER (BIT(30) | BIT(31)) + +#define TX_STAT_TBC 0xffff +#define TX_STAT_TXINTR BIT(16) +#define TX_STAT_DEF BIT(17) +#define TX_STAT_TXCP BIT(19) +#define TX_STAT_EXDEF BIT(20) +#define TX_STAT_NCS BIT(21) +#define TX_STAT_TXBT BIT(22) +#define TX_STAT_LC BIT(23) +#define TX_STAT_TXHA BIT(24) +#define TX_STAT_PAU BIT(25) +#define TX_STAT_SQE BIT(26) + +/* rx and tx owner bit */ +#define RX_OWEN_DMA BIT(31) +#define RX_OWEN_CPU 0x00 //bit 30 & bit 31 +#define TX_OWEN_DMA BIT(31) +#define TX_OWEN_CPU (~(BIT(31))) + +/* tx frame desc controller bit */ +#define MACTXINTEN 0x04 +#define CRCMODE 0x02 +#define PADDINGMODE 0x01 + +/* fftcr controller bit */ +#define RXTHD 0x03 +#define TXTHD (BIT(8) | BIT(9)) +#define BLENGTH BIT(21) + +/* global setting for driver */ +#define RX_DESC_SIZE 128 +#define TX_DESC_SIZE 64 +#define MAX_RBUFF_SZ 0x600 +#define MAX_TBUFF_SZ 0x600 +#define TX_TIMEOUT 50 +#define DELAY 1000 +#define CAM0 0x0 +#define RX_POLL_SIZE (RX_DESC_SIZE / 2) +#define MII_TIMEOUT 100 +#define GCR_INTCR 0x3c +#define INTCR_R1EN BIT(5) + +enum MIIDA_MDCCR_T { + MIIDA_MDCCR_4 = 0x00, + MIIDA_MDCCR_6 = 0x01, + MIIDA_MDCCR_8 = 0x02, + MIIDA_MDCCR_12 = 0x03, + MIIDA_MDCCR_16 = 0x04, + MIIDA_MDCCR_20 = 0x05, + MIIDA_MDCCR_24 = 0x06, + MIIDA_MDCCR_28 = 0x07, + MIIDA_MDCCR_30 = 0x08, + MIIDA_MDCCR_32 = 0x09, + MIIDA_MDCCR_36 = 0x0A, + MIIDA_MDCCR_40 = 0x0B, + MIIDA_MDCCR_44 = 0x0C, + MIIDA_MDCCR_48 = 0x0D, + MIIDA_MDCCR_54 = 0x0E, + MIIDA_MDCCR_60 = 0x0F, +}; + +DECLARE_GLOBAL_DATA_PTR; + +static int npcm750_mdio_read(struct mii_dev *bus, int addr, int devad, int regs) +{ + struct npcm750_eth_dev *priv = (struct npcm750_eth_dev *)bus->priv; + struct emc_regs *reg = priv->emc_regs_p; + u32 start, val; + int timeout = CONFIG_MDIO_TIMEOUT; + + val = (addr << 0x08) | regs | PHYBUSY | (MIIDA_MDCCR_60 << 20); + writel(val, ®->miida); + + start = get_timer(0); + while (get_timer(start) < timeout) { + if (!(readl(®->miida) & PHYBUSY)) { + val = readl(®->miid); + return val; + } + udelay(10); + }; + return -ETIMEDOUT; +} + +static int npcm750_mdio_write(struct mii_dev *bus, int addr, int devad, int regs, + u16 val) +{ + struct npcm750_eth_dev *priv = (struct npcm750_eth_dev *)bus->priv; + struct emc_regs *reg = priv->emc_regs_p; + ulong start; + int ret = -ETIMEDOUT, timeout = CONFIG_MDIO_TIMEOUT; + + writel(val, ®->miid); + writel((addr << 0x08) | regs | PHYBUSY | PHYWR | (MIIDA_MDCCR_60 << 20), ®->miida); + + start = get_timer(0); + while (get_timer(start) < timeout) { + if (!(readl(®->miida) & PHYBUSY)) { + ret = 0; + break; + } + udelay(10); + }; + return ret; +} + +static int npcm750_mdio_reset(struct mii_dev *bus) +{ + return 0; +} + +static int npcm750_mdio_init(const char *name, struct npcm750_eth_dev *priv) +{ + struct emc_regs *reg = priv->emc_regs_p; + struct mii_dev *bus = mdio_alloc(); + + if (!bus) { + printf("Failed to allocate MDIO bus\n"); + return -ENOMEM; + } + + bus->read = npcm750_mdio_read; + bus->write = npcm750_mdio_write; + snprintf(bus->name, sizeof(bus->name), "%s", name); + bus->reset = npcm750_mdio_reset; + + bus->priv = (void *)priv; + + writel(readl(®->mcmdr) | MCMDR_ENMDC, ®->mcmdr); + return mdio_register(bus); +} + +static void npcm750_tx_descs_init(struct npcm750_eth_dev *priv) +{ + struct emc_regs *reg = priv->emc_regs_p; + struct npcm750_txbd *desc_table_p = &priv->tdesc[0]; + struct npcm750_txbd *desc_p; + u8 *txbuffs = &priv->txbuffs[0]; + u32 idx; + + writel((u32)desc_table_p, ®->txdlsa); + priv->curr_txd = desc_table_p; + + for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) { + desc_p = &desc_table_p[idx]; + desc_p->buffer = (u32)&txbuffs[idx * PKTSIZE_ALIGN]; + desc_p->sl = 0; + desc_p->mode = 0; + desc_p->mode = TX_OWEN_CPU | PADDINGMODE | CRCMODE | MACTXINTEN; + if (idx < (CONFIG_TX_DESCR_NUM - 1)) + desc_p->next = (u32)&desc_table_p[idx + 1]; + else + desc_p->next = (u32)&priv->tdesc[0]; + } + flush_dcache_range((ulong)&desc_table_p[0], + (ulong)&desc_table_p[CONFIG_TX_DESCR_NUM]); +} + +static void npcm750_rx_descs_init(struct npcm750_eth_dev *priv) +{ + struct emc_regs *reg = priv->emc_regs_p; + struct npcm750_rxbd *desc_table_p = &priv->rdesc[0]; + struct npcm750_rxbd *desc_p; + u8 *rxbuffs = &priv->rxbuffs[0]; + u32 idx; + + flush_dcache_range((ulong)priv->rxbuffs[0], + (ulong)priv->rxbuffs[CONFIG_RX_DESCR_NUM]); + + writel((u32)desc_table_p, ®->rxdlsa); + priv->curr_rxd = desc_table_p; + + for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) { + desc_p = &desc_table_p[idx]; + desc_p->sl = RX_OWEN_DMA; + desc_p->buffer = (u32)&rxbuffs[idx * PKTSIZE_ALIGN]; + if (idx < (CONFIG_RX_DESCR_NUM - 1)) + desc_p->next = (u32)&desc_table_p[idx + 1]; + else + desc_p->next = (u32)&priv->rdesc[0]; + } + flush_dcache_range((ulong)&desc_table_p[0], + (ulong)&desc_table_p[CONFIG_RX_DESCR_NUM]); +} + +static void npcm750_set_fifo_threshold(struct npcm750_eth_dev *priv) +{ + struct emc_regs *reg = priv->emc_regs_p; + unsigned int val; + + val = RXTHD | TXTHD | BLENGTH; + writel(val, ®->fftcr); +} + +static void npcm750_set_global_maccmd(struct npcm750_eth_dev *priv) +{ + struct emc_regs *reg = priv->emc_regs_p; + unsigned int val; + + val = readl(®->mcmdr); + val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | MCMDR_NDEF; + writel(val, ®->mcmdr); +} + +static void npcm750_set_cam(struct npcm750_eth_dev *priv, + unsigned int x, unsigned char *pval) +{ + struct emc_regs *reg = priv->emc_regs_p; + unsigned int msw, lsw; + + msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3]; + lsw = (pval[4] << 24) | (pval[5] << 16); + + writel(lsw, ®->cam0l + x * CAM_ENTRY_SIZE); + writel(msw, ®->cam0m + x * CAM_ENTRY_SIZE); + writel(readl(®->camen) | CAM0EN, ®->camen); + writel(CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AUP, ®->camcmr); +} + +static void npcm750_adjust_link(struct emc_regs *reg, + struct phy_device *phydev) +{ + u32 val = readl(®->mcmdr); + + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); + return; + } + + if (phydev->speed == 100) + val |= MCMDR_OPMOD; + else + val &= ~MCMDR_OPMOD; + + if (phydev->duplex) + val |= MCMDR_FDUP; + else + val &= ~MCMDR_FDUP; + + writel(val, ®->mcmdr); + + debug("Speed: %d, %s duplex%s\n", phydev->speed, + (phydev->duplex) ? "full" : "half", + (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); +} + +static int npcm750_phy_init(struct npcm750_eth_dev *priv, void *dev) +{ + struct phy_device *phydev; + int ret; + u32 address = 0x0; + + phydev = phy_connect(priv->bus, address, dev, priv->interface); + if (!phydev) + return -ENODEV; + + if (priv->max_speed) { + ret = phy_set_supported(phydev, priv->max_speed); + if (ret) + return ret; + } + phydev->advertising = phydev->supported; + + priv->phydev = phydev; + phy_config(phydev); + return 0; +} + +static int npcm750_eth_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct npcm750_eth_dev *priv = dev_get_priv(dev); + struct emc_regs *reg = priv->emc_regs_p; + u8 *enetaddr = pdata->enetaddr; + int ret; + + writel(readl(®->mcmdr) & ~MCMDR_TXON & ~MCMDR_RXON, ®->mcmdr); + + writel(readl(®->mcmdr) | MCMDR_SWR, ®->mcmdr); + do { + ret = readl(®->mcmdr); + } while (ret & MCMDR_SWR); + + npcm750_rx_descs_init(priv); + npcm750_tx_descs_init(priv); + + npcm750_set_cam(priv, priv->idx, enetaddr); + npcm750_set_global_maccmd(priv); + npcm750_set_fifo_threshold(priv); + + /* Start up the PHY */ + ret = phy_startup(priv->phydev); + if (ret) { + printf("Could not initialize PHY\n"); + return ret; + } + + npcm750_adjust_link(reg, priv->phydev); + writel(readl(®->mcmdr) | MCMDR_TXON | MCMDR_RXON, ®->mcmdr); + + return 0; +} + +static int npcm750_eth_send(struct udevice *dev, void *packet, int length) +{ + struct npcm750_eth_dev *priv = dev_get_priv(dev); + struct emc_regs *reg = priv->emc_regs_p; + struct npcm750_txbd *desc_p; + struct npcm750_txbd *next_desc_p; + + desc_p = priv->curr_txd; + + invalidate_dcache_range((ulong)desc_p, (ulong)(desc_p + 1)); + /* Check if the descriptor is owned by CPU */ + if (desc_p->mode & TX_OWEN_DMA) { + next_desc_p = (struct npcm750_txbd *)desc_p->next; + + while ((next_desc_p != desc_p) && (next_desc_p->mode & TX_OWEN_DMA)) + next_desc_p = (struct npcm750_txbd *)next_desc_p->next; + + if (next_desc_p == desc_p) { + struct emc_regs *reg = priv->emc_regs_p; + + writel(0, ®->tsdr); + serial_printf("TX: overflow and exit\n"); + return -EPERM; + } + + desc_p = next_desc_p; + } + + memcpy((void *)desc_p->buffer, packet, length); + flush_dcache_range((ulong)desc_p->buffer, + (ulong)desc_p->buffer + roundup(length, ARCH_DMA_MINALIGN)); + desc_p->sl = 0; + desc_p->sl = length & TX_STAT_TBC; + desc_p->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE; + flush_dcache_range((ulong)desc_p, (ulong)(desc_p + 1)); + + if (!(readl(®->mcmdr) & MCMDR_TXON)) + writel(readl(®->mcmdr) | MCMDR_TXON, ®->mcmdr); + priv->curr_txd = (struct npcm750_txbd *)priv->curr_txd->next; + + writel(0, ®->tsdr); + return 0; +} + +static int npcm750_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct npcm750_eth_dev *priv = dev_get_priv(dev); + struct npcm750_rxbd *desc_p; + struct npcm750_rxbd *next_desc_p; + int length = -1; + + desc_p = priv->curr_rxd; + invalidate_dcache_range((ulong)desc_p, (ulong)(desc_p + 1)); + + if ((desc_p->sl & RX_STAT_OWNER) == RX_OWEN_DMA) { + next_desc_p = (struct npcm750_rxbd *)desc_p->next; + while ((next_desc_p != desc_p) && + ((next_desc_p->sl & RX_STAT_OWNER) == RX_OWEN_CPU)) { + next_desc_p = (struct npcm750_rxbd *)next_desc_p->next; + } + + if (next_desc_p == desc_p) { + struct emc_regs *reg = priv->emc_regs_p; + + writel(0, ®->rsdr); + serial_printf("RX: overflow and exit\n"); + return -EPERM; + } + desc_p = next_desc_p; + } + + /* Check if the descriptor is owned by CPU */ + if ((desc_p->sl & RX_STAT_OWNER) == RX_OWEN_CPU) { + if (desc_p->sl & RX_STAT_RXGD) { + length = desc_p->sl & RX_STAT_RBC; + invalidate_dcache_range((ulong)desc_p->buffer, + (ulong)(desc_p->buffer + roundup(length, + ARCH_DMA_MINALIGN))); + *packetp = (u8 *)(u32)desc_p->buffer; + priv->curr_rxd = desc_p; + } + } + return length; +} + +static int npcm750_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct npcm750_eth_dev *priv = dev_get_priv(dev); + struct emc_regs *reg = priv->emc_regs_p; + struct npcm750_rxbd *desc_p = priv->curr_rxd; + + /* + * Make the current descriptor valid again and go to + * the next one + */ + desc_p->sl |= RX_OWEN_DMA; + flush_dcache_range((ulong)desc_p, (ulong)(desc_p + 1)); + priv->curr_rxd = (struct npcm750_rxbd *)priv->curr_rxd->next; + writel(0, ®->rsdr); + + return 0; +} + +static void npcm750_eth_stop(struct udevice *dev) +{ + struct npcm750_eth_dev *priv = dev_get_priv(dev); + struct emc_regs *reg = priv->emc_regs_p; + + writel(readl(®->mcmdr) & ~MCMDR_TXON, ®->mcmdr); + writel(readl(®->mcmdr) & ~MCMDR_RXON, ®->mcmdr); + priv->curr_txd = (struct npcm750_txbd *)readl(®->txdlsa); + priv->curr_rxd = (struct npcm750_rxbd *)readl(®->rxdlsa); + phy_shutdown(priv->phydev); +} + +static int npcm750_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct npcm750_eth_dev *priv = dev_get_priv(dev); + + npcm750_set_cam(priv, CAM0, pdata->enetaddr); + return 0; +} + +static int npcm750_eth_bind(struct udevice *dev) +{ + return 0; +} + +static int npcm750_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct npcm750_eth_dev *priv = dev_get_priv(dev); + u32 iobase = pdata->iobase; + int ret; + + memset(priv, 0, sizeof(struct npcm750_eth_dev)); + ret = dev_read_u32(dev, "id", &priv->idx); + if (ret) { + printf("failed to get id\n"); + return -EINVAL; + } + + priv->gcr_regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-gcr"); + if (IS_ERR(priv->gcr_regmap)) + return -EINVAL; + + priv->emc_regs_p = (struct emc_regs *)iobase; + priv->interface = pdata->phy_interface; + priv->max_speed = pdata->max_speed; + + if (priv->idx == 0) { + /* Enable RMII for EMC1 module */ + regmap_update_bits(priv->gcr_regmap, GCR_INTCR, INTCR_R1EN, INTCR_R1EN); + } + + npcm750_mdio_init(dev->name, priv); + priv->bus = miiphy_get_dev_by_name(dev->name); + + ret = npcm750_phy_init(priv, dev); + + return ret; +} + +static int npcm750_eth_remove(struct udevice *dev) +{ + struct npcm750_eth_dev *priv = dev_get_priv(dev); + + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + return 0; +} + +static const struct eth_ops npcm750_eth_ops = { + .start = npcm750_eth_start, + .send = npcm750_eth_send, + .recv = npcm750_eth_recv, + .free_pkt = npcm750_eth_free_pkt, + .stop = npcm750_eth_stop, + .write_hwaddr = npcm750_eth_write_hwaddr, +}; + +static int npcm750_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct npcm750_eth_pdata *npcm750_pdata = dev_get_plat(dev); + struct eth_pdata *pdata = &npcm750_pdata->eth_pdata; + const char *phy_mode; + const fdt32_t *cell; + int ret = 0; + + pdata->iobase = (phys_addr_t)dev_read_addr_ptr(dev); + + pdata->phy_interface = -1; + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + printf("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + + pdata->max_speed = 0; + cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL); + if (cell) + pdata->max_speed = fdt32_to_cpu(*cell); + + return ret; +} + +static const struct udevice_id npcm750_eth_ids[] = { + { .compatible = "nuvoton,npcm750-emc" }, + { } +}; + +U_BOOT_DRIVER(eth_npcm750) = { + .name = "eth_npcm750", + .id = UCLASS_ETH, + .of_match = npcm750_eth_ids, + .of_to_plat = npcm750_eth_ofdata_to_platdata, + .bind = npcm750_eth_bind, + .probe = npcm750_eth_probe, + .remove = npcm750_eth_remove, + .ops = &npcm750_eth_ops, + .priv_auto = sizeof(struct npcm750_eth_dev), + .plat_auto = sizeof(struct npcm750_eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; From f44bf737841bb90a92b6c7eca9a8ee4075febe57 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Tue, 17 May 2022 15:16:39 -0700 Subject: [PATCH 10/17] net: ftgmac100: use bus name in mdio error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we'd been using a device name retrieved via ftgmac100_data->phydev, but the mdio read/write functions may be called before that member is initialized in ftgmac100_phy_init(), leading to a NULL pointer dereference while printing the error message issued if the mdio access fails. We can instead use bus->name, which is already available at that point. Signed-off-by: Zev Weiss Fixes: 538e75d3fc54 ("net: ftgmac100: add MDIO bus and phylib support") Reviewed-by: Cédric Le Goater --- drivers/net/ftgmac100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 78779d7d60b..74261d14e54 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -119,7 +119,7 @@ static int ftgmac100_mdio_read(struct mii_dev *bus, int phy_addr, int dev_addr, FTGMAC100_MDIO_TIMEOUT_USEC); if (ret) { pr_err("%s: mdio read failed (phy:%d reg:%x)\n", - priv->phydev->dev->name, phy_addr, reg_addr); + bus->name, phy_addr, reg_addr); return ret; } @@ -151,7 +151,7 @@ static int ftgmac100_mdio_write(struct mii_dev *bus, int phy_addr, int dev_addr, FTGMAC100_MDIO_TIMEOUT_USEC); if (ret) { pr_err("%s: mdio write failed (phy:%d reg:%x)\n", - priv->phydev->dev->name, phy_addr, reg_addr); + bus->name, phy_addr, reg_addr); } return ret; From 65f2266ed61b49bbc997e151bc14702bfbbfcef9 Mon Sep 17 00:00:00 2001 From: Ramon Fried Date: Sun, 5 Jun 2022 03:44:15 +0300 Subject: [PATCH 11/17] net: phy: Remove inline definitions from convinience functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The convinience functions are not that small and they caused bloated text segments because of their usage. There was no need to inline them in the first place, as they're not part of a fastpath. Signed-off-by: Ramon Fried Reviewed-by: Michael Trimarchi Reviewed-by: Marek Behún Reviewed-by: Vladimir Oltean --- drivers/net/phy/phy.c | 174 ++++++++++++++++++++++++++++++++++++++ include/phy.h | 189 ++---------------------------------------- 2 files changed, 183 insertions(+), 180 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1121b99abff..e6e17555188 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1101,3 +1101,177 @@ int phy_modify(struct phy_device *phydev, int devad, int regnum, u16 mask, return phy_write(phydev, devad, regnum, (ret & ~mask) | set); } + +/** + * phy_read - Convenience function for reading a given PHY register + * @phydev: the phy_device struct + * @devad: The MMD to read from + * @regnum: register number to read + * @return: value for success or negative errno for failure + */ +int phy_read(struct phy_device *phydev, int devad, int regnum) +{ + struct mii_dev *bus = phydev->bus; + + if (!bus || !bus->read) { + debug("%s: No bus configured\n", __func__); + return -1; + } + + return bus->read(bus, phydev->addr, devad, regnum); +} + +/** + * phy_write - Convenience function for writing a given PHY register + * @phydev: the phy_device struct + * @devad: The MMD to read from + * @regnum: register number to write + * @val: value to write to @regnum + * @return: 0 for success or negative errno for failure + */ +int phy_write(struct phy_device *phydev, int devad, int regnum, u16 val) +{ + struct mii_dev *bus = phydev->bus; + + if (!bus || !bus->write) { + debug("%s: No bus configured\n", __func__); + return -1; + } + + return bus->write(bus, phydev->addr, devad, regnum, val); +} + +/** + * phy_mmd_start_indirect - Convenience function for writing MMD registers + * @phydev: the phy_device struct + * @devad: The MMD to read from + * @regnum: register number to write + * @return: None + */ +void phy_mmd_start_indirect(struct phy_device *phydev, int devad, int regnum) +{ + /* Write the desired MMD Devad */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad); + + /* Write the desired MMD register address */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, regnum); + + /* Select the Function : DATA with no post increment */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, + (devad | MII_MMD_CTRL_NOINCR)); +} + +/** + * phy_read_mmd - Convenience function for reading a register + * from an MMD on a given PHY. + * @phydev: The phy_device struct + * @devad: The MMD to read from + * @regnum: The register on the MMD to read + * @return: Value for success or negative errno for failure + */ +int phy_read_mmd(struct phy_device *phydev, int devad, int regnum) +{ + struct phy_driver *drv = phydev->drv; + + if (regnum > (u16)~0 || devad > 32) + return -EINVAL; + + /* driver-specific access */ + if (drv->read_mmd) + return drv->read_mmd(phydev, devad, regnum); + + /* direct C45 / C22 access */ + if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES || + devad == MDIO_DEVAD_NONE || !devad) + return phy_read(phydev, devad, regnum); + + /* indirect C22 access */ + phy_mmd_start_indirect(phydev, devad, regnum); + + /* Read the content of the MMD's selected register */ + return phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA); +} + +/** + * phy_write_mmd - Convenience function for writing a register + * on an MMD on a given PHY. + * @phydev: The phy_device struct + * @devad: The MMD to read from + * @regnum: The register on the MMD to read + * @val: value to write to @regnum + * @return: 0 for success or negative errno for failure + */ +int phy_write_mmd(struct phy_device *phydev, int devad, int regnum, u16 val) +{ + struct phy_driver *drv = phydev->drv; + + if (regnum > (u16)~0 || devad > 32) + return -EINVAL; + + /* driver-specific access */ + if (drv->write_mmd) + return drv->write_mmd(phydev, devad, regnum, val); + + /* direct C45 / C22 access */ + if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES || + devad == MDIO_DEVAD_NONE || !devad) + return phy_write(phydev, devad, regnum, val); + + /* indirect C22 access */ + phy_mmd_start_indirect(phydev, devad, regnum); + + /* Write the data into MMD's selected register */ + return phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val); +} + +/** + * phy_set_bits_mmd - Convenience function for setting bits in a register + * on MMD + * @phydev: the phy_device struct + * @devad: the MMD containing register to modify + * @regnum: register number to modify + * @val: bits to set + * @return: 0 for success or negative errno for failure + */ +int phy_set_bits_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) +{ + int value, ret; + + value = phy_read_mmd(phydev, devad, regnum); + if (value < 0) + return value; + + value |= val; + + ret = phy_write_mmd(phydev, devad, regnum, value); + if (ret < 0) + return ret; + + return 0; +} + +/** + * phy_clear_bits_mmd - Convenience function for clearing bits in a register + * on MMD + * @phydev: the phy_device struct + * @devad: the MMD containing register to modify + * @regnum: register number to modify + * @val: bits to clear + * @return: 0 for success or negative errno for failure + */ +int phy_clear_bits_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) +{ + int value, ret; + + value = phy_read_mmd(phydev, devad, regnum); + if (value < 0) + return value; + + value &= ~val; + + ret = phy_write_mmd(phydev, devad, regnum, value); + if (ret < 0) + return ret; + + return 0; +} diff --git a/include/phy.h b/include/phy.h index b3295957106..ad2096ca84f 100644 --- a/include/phy.h +++ b/include/phy.h @@ -177,186 +177,6 @@ struct fixed_link { int asym_pause; }; -/** - * phy_read - Convenience function for reading a given PHY register - * @phydev: the phy_device struct - * @devad: The MMD to read from - * @regnum: register number to read - * @return: value for success or negative errno for failure - */ -static inline int phy_read(struct phy_device *phydev, int devad, int regnum) -{ - struct mii_dev *bus = phydev->bus; - - if (!bus || !bus->read) { - debug("%s: No bus configured\n", __func__); - return -1; - } - - return bus->read(bus, phydev->addr, devad, regnum); -} - -/** - * phy_write - Convenience function for writing a given PHY register - * @phydev: the phy_device struct - * @devad: The MMD to read from - * @regnum: register number to write - * @val: value to write to @regnum - * @return: 0 for success or negative errno for failure - */ -static inline int phy_write(struct phy_device *phydev, int devad, int regnum, - u16 val) -{ - struct mii_dev *bus = phydev->bus; - - if (!bus || !bus->write) { - debug("%s: No bus configured\n", __func__); - return -1; - } - - return bus->write(bus, phydev->addr, devad, regnum, val); -} - -/** - * phy_mmd_start_indirect - Convenience function for writing MMD registers - * @phydev: the phy_device struct - * @devad: The MMD to read from - * @regnum: register number to write - * @return: None - */ -static inline void phy_mmd_start_indirect(struct phy_device *phydev, int devad, - int regnum) -{ - /* Write the desired MMD Devad */ - phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad); - - /* Write the desired MMD register address */ - phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, regnum); - - /* Select the Function : DATA with no post increment */ - phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, - (devad | MII_MMD_CTRL_NOINCR)); -} - -/** - * phy_read_mmd - Convenience function for reading a register - * from an MMD on a given PHY. - * @phydev: The phy_device struct - * @devad: The MMD to read from - * @regnum: The register on the MMD to read - * @return: Value for success or negative errno for failure - */ -static inline int phy_read_mmd(struct phy_device *phydev, int devad, - int regnum) -{ - struct phy_driver *drv = phydev->drv; - - if (regnum > (u16)~0 || devad > 32) - return -EINVAL; - - /* driver-specific access */ - if (drv->read_mmd) - return drv->read_mmd(phydev, devad, regnum); - - /* direct C45 / C22 access */ - if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES || - devad == MDIO_DEVAD_NONE || !devad) - return phy_read(phydev, devad, regnum); - - /* indirect C22 access */ - phy_mmd_start_indirect(phydev, devad, regnum); - - /* Read the content of the MMD's selected register */ - return phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA); -} - -/** - * phy_write_mmd - Convenience function for writing a register - * on an MMD on a given PHY. - * @phydev: The phy_device struct - * @devad: The MMD to read from - * @regnum: The register on the MMD to read - * @val: value to write to @regnum - * @return: 0 for success or negative errno for failure - */ -static inline int phy_write_mmd(struct phy_device *phydev, int devad, - int regnum, u16 val) -{ - struct phy_driver *drv = phydev->drv; - - if (regnum > (u16)~0 || devad > 32) - return -EINVAL; - - /* driver-specific access */ - if (drv->write_mmd) - return drv->write_mmd(phydev, devad, regnum, val); - - /* direct C45 / C22 access */ - if ((drv->features & PHY_10G_FEATURES) == PHY_10G_FEATURES || - devad == MDIO_DEVAD_NONE || !devad) - return phy_write(phydev, devad, regnum, val); - - /* indirect C22 access */ - phy_mmd_start_indirect(phydev, devad, regnum); - - /* Write the data into MMD's selected register */ - return phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val); -} - -/** - * phy_set_bits_mmd - Convenience function for setting bits in a register - * on MMD - * @phydev: the phy_device struct - * @devad: the MMD containing register to modify - * @regnum: register number to modify - * @val: bits to set - * @return: 0 for success or negative errno for failure - */ -static inline int phy_set_bits_mmd(struct phy_device *phydev, int devad, - u32 regnum, u16 val) -{ - int value, ret; - - value = phy_read_mmd(phydev, devad, regnum); - if (value < 0) - return value; - - value |= val; - - ret = phy_write_mmd(phydev, devad, regnum, value); - if (ret < 0) - return ret; - - return 0; -} - -/** - * phy_clear_bits_mmd - Convenience function for clearing bits in a register - * on MMD - * @phydev: the phy_device struct - * @devad: the MMD containing register to modify - * @regnum: register number to modify - * @val: bits to clear - * @return: 0 for success or negative errno for failure - */ -static inline int phy_clear_bits_mmd(struct phy_device *phydev, int devad, - u32 regnum, u16 val) -{ - int value, ret; - - value = phy_read_mmd(phydev, devad, regnum); - if (value < 0) - return value; - - value &= ~val; - - ret = phy_write_mmd(phydev, devad, regnum, value); - if (ret < 0) - return ret; - - return 0; -} - #ifdef CONFIG_PHYLIB_10G extern struct phy_driver gen10g_driver; #endif @@ -508,6 +328,15 @@ static inline ofnode phy_get_ofnode(struct phy_device *phydev) return ofnode_null(); } #endif + +int phy_read(struct phy_device *phydev, int devad, int regnum); +int phy_write(struct phy_device *phydev, int devad, int regnum, u16 val); +void phy_mmd_start_indirect(struct phy_device *phydev, int devad, int regnum); +int phy_read_mmd(struct phy_device *phydev, int devad, int regnum); +int phy_write_mmd(struct phy_device *phydev, int devad, int regnum, u16 val); +int phy_set_bits_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val); +int phy_clear_bits_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val); + int phy_startup(struct phy_device *phydev); int phy_config(struct phy_device *phydev); int phy_shutdown(struct phy_device *phydev); From 8a3b69d2f257570afef273a579a8b22ec4160e9f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Thu, 30 Jun 2022 11:09:41 +0200 Subject: [PATCH 12/17] net: dwc_eth_qos: cosmetic: reorder include files Reorder include files in the U-Boot expected order. Signed-off-by: Patrick Delaunay Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 43af7d91f81..57618f0758f 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #ifdef CONFIG_ARCH_IMX8M #include #include From ebb8ff61ad97bd1c9721b049497ddb80030eeb0f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 11 Jul 2022 19:40:13 +0200 Subject: [PATCH 13/17] net: phy: possible NULL dereference in fixed_phy_create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We check if phydev is NULL. Only but if it is non-NULL we set one component of phydev. But even if it is NULL we set another. We should not dereference NULL in either case. Fixes: e24b58f5ed4f ("net: phy: don't require PHY interface mode during PHY creation") Signed-off-by: Heinrich Schuchardt Reviewed-by: Marek Behún --- drivers/net/phy/phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e6e17555188..0350afdd1b6 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -984,10 +984,10 @@ struct phy_device *fixed_phy_create(ofnode node) } phydev = phy_device_create(NULL, 0, PHY_FIXED_ID, false); - if (phydev) + if (phydev) { phydev->node = subnode; - - phydev->interface = ofnode_read_phy_mode(node); + phydev->interface = ofnode_read_phy_mode(node); + } return phydev; } From 5a28aa6a7b2c9fff1d852ba0093f47987c5b0235 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 13 Jul 2022 10:59:44 +0900 Subject: [PATCH 14/17] net: ave: Add capability of rgmii-id mode This allows you to specify the type of rgmii-id that will enable phy internal delay in ethernet phy-mode. This adds all RGMII cases to all of get_pinmode() except LD11, because LD11 SoC doesn't support RGMII due to the constraint of the hardware. When RGMII phy mode is specified in the devicetree for LD11, the driver will abort with an error. Signed-off-by: Kunihiko Hayashi Reviewed-by: Ramon Fried --- drivers/net/sni_ave.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/sni_ave.c b/drivers/net/sni_ave.c index 58276a40c77..014b070d9e5 100644 --- a/drivers/net/sni_ave.c +++ b/drivers/net/sni_ave.c @@ -483,7 +483,10 @@ static int ave_start(struct udevice *dev) priv->rx_siz = (PKTSIZE_ALIGN - priv->rx_off); val = 0; - if (priv->phy_mode != PHY_INTERFACE_MODE_RGMII) + if (priv->phy_mode != PHY_INTERFACE_MODE_RGMII && + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_ID && + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_RXID && + priv->phy_mode != PHY_INTERFACE_MODE_RGMII_TXID) val |= AVE_CFGR_MII; writel(val, priv->iobase + AVE_CFGR); @@ -639,6 +642,9 @@ static int ave_pro4_get_pinmode(struct ave_private *priv) break; case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: break; default: return -EINVAL; @@ -693,6 +699,9 @@ static int ave_ld20_get_pinmode(struct ave_private *priv) val = SG_ETPINMODE_RMII(0); break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: break; default: return -EINVAL; @@ -720,6 +729,9 @@ static int ave_pxs3_get_pinmode(struct ave_private *priv) val = SG_ETPINMODE_RMII(priv->regmap_arg); break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: break; default: return -EINVAL; From dd8c3136aa8abb61281cc32f1ce19e1f84a66922 Mon Sep 17 00:00:00 2001 From: Kunihiko Hayashi Date: Wed, 13 Jul 2022 10:59:45 +0900 Subject: [PATCH 15/17] ARM: dts: uniphier: Change phy-mode to RGMII-ID to enable delay pins UniPhier LD20, PXs2 and PXs3 boards have ethernet phy that has RX/TX delays of RGMII interface using pull-ups on the RXDLY and TXDLY pins. So should set the phy-mode to "rgmii-id" to show that RX/TX delays are enabled. Signed-off-by: Kunihiko Hayashi Reviewed-by: Ramon Fried --- arch/arm/dts/uniphier-ld20.dtsi | 2 +- arch/arm/dts/uniphier-pxs2.dtsi | 2 +- arch/arm/dts/uniphier-pxs3.dtsi | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/dts/uniphier-ld20.dtsi b/arch/arm/dts/uniphier-ld20.dtsi index 5e7143ed012..4549935c421 100644 --- a/arch/arm/dts/uniphier-ld20.dtsi +++ b/arch/arm/dts/uniphier-ld20.dtsi @@ -734,7 +734,7 @@ clocks = <&sys_clk 6>; reset-names = "ether"; resets = <&sys_rst 6>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; local-mac-address = [00 00 00 00 00 00]; socionext,syscon-phy-mode = <&soc_glue 0>; diff --git a/arch/arm/dts/uniphier-pxs2.dtsi b/arch/arm/dts/uniphier-pxs2.dtsi index 899ff379c9b..7a8b6c10f4d 100644 --- a/arch/arm/dts/uniphier-pxs2.dtsi +++ b/arch/arm/dts/uniphier-pxs2.dtsi @@ -583,7 +583,7 @@ clocks = <&sys_clk 6>; reset-names = "ether"; resets = <&sys_rst 6>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; local-mac-address = [00 00 00 00 00 00]; socionext,syscon-phy-mode = <&soc_glue 0>; diff --git a/arch/arm/dts/uniphier-pxs3.dtsi b/arch/arm/dts/uniphier-pxs3.dtsi index c4344926d95..004656c992b 100644 --- a/arch/arm/dts/uniphier-pxs3.dtsi +++ b/arch/arm/dts/uniphier-pxs3.dtsi @@ -564,7 +564,7 @@ clocks = <&sys_clk 6>; reset-names = "ether"; resets = <&sys_rst 6>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; local-mac-address = [00 00 00 00 00 00]; socionext,syscon-phy-mode = <&soc_glue 0>; @@ -585,7 +585,7 @@ clocks = <&sys_clk 7>; reset-names = "ether"; resets = <&sys_rst 7>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; local-mac-address = [00 00 00 00 00 00]; socionext,syscon-phy-mode = <&soc_glue 1>; From acce23b8af7091354d3701638b4d06489e7c766c Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 2 Aug 2022 10:55:25 +0200 Subject: [PATCH 16/17] net: dwc_eth_qos: Add eqos_get_enetaddr callback for tegra186 Add .eqos_get_enetaddr callback defined as eqos_null_ops() to avoid illegal access. Fixes: a624251461bf ("net: dwc_eth_qos: introduce eqos hook eqos_get_enetaddr") Signed-off-by: Patrice Chotard Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 57618f0758f..21e9b6ab174 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1606,6 +1606,7 @@ static struct eqos_ops eqos_tegra186_ops = { .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, .eqos_disable_calibration = eqos_disable_calibration_tegra186, .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, + .eqos_get_enetaddr = eqos_null_ops, .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 }; From 5bd4f31fea36cf4106d6314efd33ba49efcaeded Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 2 Aug 2022 10:55:26 +0200 Subject: [PATCH 17/17] net: dwc_eth_qos: Add eqos_get_enetaddr callback for stm32 Add .eqos_get_enetaddr callback defined as eqos_null_ops() to avoid illegal access. Fixes: a624251461bf ("net: dwc_eth_qos: introduce eqos hook eqos_get_enetaddr") Signed-off-by: Patrice Chotard Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 21e9b6ab174..001b028fa13 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1635,6 +1635,7 @@ static struct eqos_ops eqos_stm32_ops = { .eqos_calibrate_pads = eqos_null_ops, .eqos_disable_calibration = eqos_null_ops, .eqos_set_tx_clk_speed = eqos_null_ops, + .eqos_get_enetaddr = eqos_null_ops, .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 };