diff options
author | Tom Rini <trini@konsulko.com> | 2023-11-06 09:45:33 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2023-11-06 09:45:33 -0500 |
commit | fd0d7d7efecd22d5a9cc77cb7589c4f144a1c506 (patch) | |
tree | 931e72fdf65dbfde58b84ee4de4d7cb1f360dbcf | |
parent | a4c83bda17196bf5d1ce640844595aaeced6465e (diff) | |
parent | d44f3d21fe4420709b5a09379b809a3b92b7fa07 (diff) | |
download | u-boot-fd0d7d7efecd22d5a9cc77cb7589c4f144a1c506.zip u-boot-fd0d7d7efecd22d5a9cc77cb7589c4f144a1c506.tar.gz u-boot-fd0d7d7efecd22d5a9cc77cb7589c4f144a1c506.tar.bz2 |
Merge branch '2023-11-06-networking-updates'
- A few dhcp related improvements, be clearer to the user when we don't
have a MAC address, assorted driver/phy improvements and new drivers.
-rw-r--r-- | cmd/Kconfig | 4 | ||||
-rw-r--r-- | cmd/pxe.c | 8 | ||||
-rw-r--r-- | drivers/net/Kconfig | 17 | ||||
-rw-r--r-- | drivers/net/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/designware.c | 31 | ||||
-rw-r--r-- | drivers/net/designware.h | 1 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 36 | ||||
-rw-r--r-- | drivers/net/e1000.c | 6 | ||||
-rw-r--r-- | drivers/net/ftgmac100.c | 12 | ||||
-rw-r--r-- | drivers/net/hifemac.c | 481 | ||||
-rw-r--r-- | drivers/net/hifemac_mdio.c | 116 | ||||
-rw-r--r-- | drivers/net/mv88e6xxx.c | 94 | ||||
-rw-r--r-- | drivers/net/phy/dp83869.c | 53 | ||||
-rw-r--r-- | include/net.h | 4 | ||||
-rw-r--r-- | net/bootp.c | 21 | ||||
-rw-r--r-- | net/dhcpv6.c | 15 | ||||
-rw-r--r-- | net/eth-uclass.c | 12 | ||||
-rw-r--r-- | net/net.c | 3 |
18 files changed, 841 insertions, 75 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index fd16c3a..df6d71c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1840,6 +1840,10 @@ config BOOTP_PXE_CLIENTARCH default 0x15 if ARM default 0x0 if X86 +config BOOTP_PXE_DHCP_OPTION + bool "Request & store 'pxe_configfile' from BOOTP/DHCP server" + depends on BOOTP_PXE + config BOOTP_VCI_STRING string depends on CMD_BOOTP @@ -141,6 +141,14 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6) env_get("bootfile"), use_ipv6)) return -ENOMEM; + if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) && + pxelinux_configfile && !use_ipv6) { + if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0) + goto done; + + goto error_exit; + } + if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) && pxelinux_configfile && use_ipv6) { if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 29304fd..ebab4d9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -903,6 +903,23 @@ config MEDIATEK_ETH This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. +config HIFEMAC_ETH + bool "HiSilicon Fast Ethernet Controller" + select DM_CLK + select DM_RESET + select PHYLIB + help + This driver supports HIFEMAC Ethernet controller found on + HiSilicon SoCs. + +config HIFEMAC_MDIO + bool "HiSilicon Fast Ethernet Controller MDIO interface" + depends on DM_MDIO + select DM_CLK + help + This driver supports the internal MDIO interface of HIFEMAC + Ethernet controller. + config HIGMACV300_ETH bool "HiSilicon Gigabit Ethernet Controller" select DM_RESET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1d444f5..1ce6fea 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -47,6 +47,8 @@ obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_FTGMAC100) += ftgmac100.o obj-$(CONFIG_FTMAC100) += ftmac100.o obj-$(CONFIG_GMAC_ROCKCHIP) += gmac_rockchip.o +obj-$(CONFIG_HIFEMAC_ETH) += hifemac.o +obj-$(CONFIG_HIFEMAC_MDIO) += hifemac_mdio.o obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o obj-$(CONFIG_KSZ9477) += ksz9477.o diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 20b86e7..a174344 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -19,6 +19,7 @@ #include <net.h> #include <pci.h> #include <reset.h> +#include <phys2bus.h> #include <asm/cache.h> #include <dm/device_compat.h> #include <dm/device-internal.h> @@ -232,8 +233,10 @@ static void tx_descs_init(struct dw_eth_dev *priv) for (idx = 0; idx < CFG_TX_DESCR_NUM; idx++) { desc_p = &desc_table_p[idx]; - desc_p->dmamac_addr = (ulong)&txbuffs[idx * CFG_ETH_BUFSIZE]; - desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1]; + desc_p->dmamac_addr = dev_phys_to_bus(priv->dev, + (ulong)&txbuffs[idx * CFG_ETH_BUFSIZE]); + desc_p->dmamac_next = dev_phys_to_bus(priv->dev, + (ulong)&desc_table_p[idx + 1]); #if defined(CONFIG_DW_ALTDESCRIPTOR) desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | @@ -251,14 +254,15 @@ static void tx_descs_init(struct dw_eth_dev *priv) } /* Correcting the last pointer of the chain */ - desc_p->dmamac_next = (ulong)&desc_table_p[0]; + desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]); /* Flush all Tx buffer descriptors at once */ flush_dcache_range((ulong)priv->tx_mac_descrtable, (ulong)priv->tx_mac_descrtable + sizeof(priv->tx_mac_descrtable)); - writel((ulong)&desc_table_p[0], &dma_p->txdesclistaddr); + writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]), + &dma_p->txdesclistaddr); priv->tx_currdescnum = 0; } @@ -280,8 +284,10 @@ static void rx_descs_init(struct dw_eth_dev *priv) for (idx = 0; idx < CFG_RX_DESCR_NUM; idx++) { desc_p = &desc_table_p[idx]; - desc_p->dmamac_addr = (ulong)&rxbuffs[idx * CFG_ETH_BUFSIZE]; - desc_p->dmamac_next = (ulong)&desc_table_p[idx + 1]; + desc_p->dmamac_addr = dev_phys_to_bus(priv->dev, + (ulong)&rxbuffs[idx * CFG_ETH_BUFSIZE]); + desc_p->dmamac_next = dev_phys_to_bus(priv->dev, + (ulong)&desc_table_p[idx + 1]); desc_p->dmamac_cntl = (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | @@ -291,14 +297,15 @@ static void rx_descs_init(struct dw_eth_dev *priv) } /* Correcting the last pointer of the chain */ - desc_p->dmamac_next = (ulong)&desc_table_p[0]; + desc_p->dmamac_next = dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]); /* Flush all Rx buffer descriptors at once */ flush_dcache_range((ulong)priv->rx_mac_descrtable, (ulong)priv->rx_mac_descrtable + sizeof(priv->rx_mac_descrtable)); - writel((ulong)&desc_table_p[0], &dma_p->rxdesclistaddr); + writel(dev_phys_to_bus(priv->dev, (ulong)&desc_table_p[0]), + &dma_p->rxdesclistaddr); priv->rx_currdescnum = 0; } @@ -448,7 +455,7 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length) ulong desc_start = (ulong)desc_p; ulong desc_end = desc_start + roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN); - ulong data_start = desc_p->dmamac_addr; + ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr); ulong data_end = data_start + roundup(length, ARCH_DMA_MINALIGN); /* * Strictly we only need to invalidate the "txrx_status" field @@ -515,7 +522,7 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp) ulong desc_start = (ulong)desc_p; ulong desc_end = desc_start + roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN); - ulong data_start = desc_p->dmamac_addr; + ulong data_start = dev_bus_to_phys(priv->dev, desc_p->dmamac_addr); ulong data_end; /* Invalidate entire buffer descriptor */ @@ -532,7 +539,8 @@ static int _dw_eth_recv(struct dw_eth_dev *priv, uchar **packetp) /* Invalidate received data */ data_end = data_start + roundup(length, ARCH_DMA_MINALIGN); invalidate_dcache_range(data_start, data_end); - *packetp = (uchar *)(ulong)desc_p->dmamac_addr; + *packetp = (uchar *)(ulong)dev_bus_to_phys(priv->dev, + desc_p->dmamac_addr); } return length; @@ -757,6 +765,7 @@ int designware_eth_probe(struct udevice *dev) goto mdio_err; } priv->bus = miiphy_get_dev_by_name(dev->name); + priv->dev = dev; ret = dw_phy_init(priv, dev); debug("%s, ret=%d\n", __func__, ret); diff --git a/drivers/net/designware.h b/drivers/net/designware.h index 9da4e90..918a386 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -241,6 +241,7 @@ struct dw_eth_dev { int clock_count; /* number of clock in clock list */ #endif + struct udevice *dev; struct phy_device *phydev; struct mii_dev *bus; }; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 18466cf..a4e3698 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -746,6 +746,7 @@ static int eqos_start(struct udevice *dev) u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl; ulong last_rx_desc; ulong desc_pad; + ulong addr64; debug("%s(dev=%p):\n", __func__, dev); @@ -1039,25 +1040,25 @@ static int eqos_start(struct udevice *dev) for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) { struct eqos_desc *rx_desc = eqos_get_desc(eqos, i, true); - rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + - (i * EQOS_MAX_PACKET_SIZE)); + + addr64 = (ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE)); + rx_desc->des0 = lower_32_bits(addr64); + rx_desc->des1 = upper_32_bits(addr64); rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; mb(); eqos->config->ops->eqos_flush_desc(rx_desc); - eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf + - (i * EQOS_MAX_PACKET_SIZE), - EQOS_MAX_PACKET_SIZE); + eqos->config->ops->eqos_inval_buffer((void *)addr64, EQOS_MAX_PACKET_SIZE); } - writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); - writel((ulong)eqos_get_desc(eqos, 0, false), - &eqos->dma_regs->ch0_txdesc_list_address); + addr64 = (ulong)eqos_get_desc(eqos, 0, false); + writel(upper_32_bits(addr64), &eqos->dma_regs->ch0_txdesc_list_haddress); + writel(lower_32_bits(addr64), &eqos->dma_regs->ch0_txdesc_list_address); writel(EQOS_DESCRIPTORS_TX - 1, &eqos->dma_regs->ch0_txdesc_ring_length); - writel(0, &eqos->dma_regs->ch0_rxdesc_list_haddress); - writel((ulong)eqos_get_desc(eqos, 0, true), - &eqos->dma_regs->ch0_rxdesc_list_address); + addr64 = (ulong)eqos_get_desc(eqos, 0, true); + writel(upper_32_bits(addr64), &eqos->dma_regs->ch0_rxdesc_list_haddress); + writel(lower_32_bits(addr64), &eqos->dma_regs->ch0_rxdesc_list_address); writel(EQOS_DESCRIPTORS_RX - 1, &eqos->dma_regs->ch0_rxdesc_ring_length); @@ -1162,8 +1163,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length) eqos->tx_desc_idx++; eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX; - tx_desc->des0 = (ulong)eqos->tx_dma_buf; - tx_desc->des1 = 0; + tx_desc->des0 = lower_32_bits((ulong)eqos->tx_dma_buf); + tx_desc->des1 = upper_32_bits((ulong)eqos->tx_dma_buf); tx_desc->des2 = length; /* * Make sure that if HW sees the _OWN write below, it will see all the @@ -1234,14 +1235,17 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) for (idx = eqos->rx_desc_idx - idx_mask; idx <= eqos->rx_desc_idx; idx++) { + ulong addr64; + rx_desc = eqos_get_desc(eqos, idx, true); rx_desc->des0 = 0; + rx_desc->des1 = 0; mb(); eqos->config->ops->eqos_flush_desc(rx_desc); eqos->config->ops->eqos_inval_buffer(packet, length); - rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + - (idx * EQOS_MAX_PACKET_SIZE)); - rx_desc->des1 = 0; + addr64 = (ulong)(eqos->rx_dma_buf + (idx * EQOS_MAX_PACKET_SIZE)); + rx_desc->des0 = lower_32_bits(addr64); + rx_desc->des1 = upper_32_bits(addr64); rx_desc->des2 = 0; /* * Make sure that if HW sees the _OWN write below, diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 41e6ba7..84a2a7c 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -5718,15 +5718,9 @@ static const struct eth_ops e1000_eth_ops = { .write_hwaddr = e1000_write_hwaddr, }; -static const struct udevice_id e1000_eth_ids[] = { - { .compatible = "intel,e1000" }, - { } -}; - U_BOOT_DRIVER(eth_e1000) = { .name = "eth_e1000", .id = UCLASS_ETH, - .of_match = e1000_eth_ids, .bind = e1000_eth_bind, .probe = e1000_eth_probe, .ops = &e1000_eth_ops, diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 587d365..9b536fd 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -13,6 +13,7 @@ #include <common.h> #include <clk.h> +#include <reset.h> #include <cpu_func.h> #include <dm.h> #include <log.h> @@ -91,6 +92,7 @@ struct ftgmac100_data { u32 max_speed; struct clk_bulk clks; + struct reset_ctl *reset_ctl; /* End of RX/TX ring buffer bits. Depend on model */ u32 rxdes0_edorr_mask; @@ -569,6 +571,8 @@ static int ftgmac100_of_to_plat(struct udevice *dev) priv->txdes0_edotr_mask = BIT(15); } + priv->reset_ctl = devm_reset_control_get_optional(dev, NULL); + return clk_get_bulk(dev, &priv->clks); } @@ -594,6 +598,12 @@ static int ftgmac100_probe(struct udevice *dev) if (ret) goto out; + if (priv->reset_ctl) { + ret = reset_deassert(priv->reset_ctl); + if (ret) + goto out; + } + /* * If DM MDIO is enabled, the MDIO bus will be initialized later in * dm_eth_phy_connect @@ -629,6 +639,8 @@ static int ftgmac100_remove(struct udevice *dev) free(priv->phydev); mdio_unregister(priv->bus); mdio_free(priv->bus); + if (priv->reset_ctl) + reset_assert(priv->reset_ctl); clk_release_bulk(&priv->clks); return 0; diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c new file mode 100644 index 0000000..b61a29e --- /dev/null +++ b/drivers/net/hifemac.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hisilicon Fast Ethernet MAC Driver + * Adapted from linux + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * Copyright (c) 2023 Yang Xiwen <forbidden405@outlook.com> + */ + +#include <dm.h> +#include <clk.h> +#include <miiphy.h> +#include <net.h> +#include <reset.h> +#include <wait_bit.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/kernel.h> + +/* MAC control register list */ +#define MAC_PORTSEL 0x0200 +#define MAC_PORTSEL_STAT_CPU BIT(0) +#define MAC_PORTSEL_RMII BIT(1) +#define MAC_PORTSET 0x0208 +#define MAC_PORTSET_DUPLEX_FULL BIT(0) +#define MAC_PORTSET_LINKED BIT(1) +#define MAC_PORTSET_SPEED_100M BIT(2) +#define MAC_SET 0x0210 +#define MAX_FRAME_SIZE 1600 +#define MAX_FRAME_SIZE_MASK GENMASK(10, 0) +#define BIT_PAUSE_EN BIT(18) +#define RX_COALESCE_SET 0x0340 +#define RX_COALESCED_FRAME_OFFSET 24 +#define RX_COALESCED_FRAMES 8 +#define RX_COALESCED_TIMER 0x74 +#define QLEN_SET 0x0344 +#define RX_DEPTH_OFFSET 8 +#define MAX_HW_FIFO_DEPTH 64 +#define HW_TX_FIFO_DEPTH 1 +#define MAX_HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH) +#define HW_RX_FIFO_DEPTH min(PKTBUFSRX, MAX_HW_RX_FIFO_DEPTH) +#define IQFRM_DES 0x0354 +#define RX_FRAME_LEN_MASK GENMASK(11, 0) +#define RX_FRAME_IN_INDEX_MASK GENMASK(17, 12) +#define IQ_ADDR 0x0358 +#define EQ_ADDR 0x0360 +#define EQFRM_LEN 0x0364 +#define ADDRQ_STAT 0x036C +#define TX_CNT_INUSE_MASK GENMASK(5, 0) +#define BIT_TX_READY BIT(24) +#define BIT_RX_READY BIT(25) +/* global control register list */ +#define GLB_HOSTMAC_L32 0x0000 +#define GLB_HOSTMAC_H16 0x0004 +#define GLB_SOFT_RESET 0x0008 +#define SOFT_RESET_ALL BIT(0) +#define GLB_FWCTRL 0x0010 +#define FWCTRL_VLAN_ENABLE BIT(0) +#define FWCTRL_FW2CPU_ENA BIT(5) +#define FWCTRL_FWALL2CPU BIT(7) +#define GLB_MACTCTRL 0x0014 +#define MACTCTRL_UNI2CPU BIT(1) +#define MACTCTRL_MULTI2CPU BIT(3) +#define MACTCTRL_BROAD2CPU BIT(5) +#define MACTCTRL_MACT_ENA BIT(7) +#define GLB_IRQ_STAT 0x0030 +#define GLB_IRQ_ENA 0x0034 +#define IRQ_ENA_PORT0_MASK GENMASK(7, 0) +#define IRQ_ENA_PORT0 BIT(18) +#define IRQ_ENA_ALL BIT(19) +#define GLB_IRQ_RAW 0x0038 +#define IRQ_INT_RX_RDY BIT(0) +#define IRQ_INT_TX_PER_PACKET BIT(1) +#define IRQ_INT_TX_FIFO_EMPTY BIT(6) +#define IRQ_INT_MULTI_RXRDY BIT(7) +#define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \ + IRQ_INT_TX_PER_PACKET | \ + IRQ_INT_TX_FIFO_EMPTY) +#define GLB_MAC_L32_BASE 0x0100 +#define GLB_MAC_H16_BASE 0x0104 +#define MACFLT_HI16_MASK GENMASK(15, 0) +#define BIT_MACFLT_ENA BIT(17) +#define BIT_MACFLT_FW2CPU BIT(21) +#define GLB_MAC_H16(reg) (GLB_MAC_H16_BASE + ((reg) * 0x8)) +#define GLB_MAC_L32(reg) (GLB_MAC_L32_BASE + ((reg) * 0x8)) +#define MAX_MAC_FILTER_NUM 8 +#define MAX_UNICAST_ADDRESSES 2 +#define MAX_MULTICAST_ADDRESSES (MAX_MAC_FILTER_NUM - \ + MAX_UNICAST_ADDRESSES) +/* software tx and rx queue number, should be power of 2 */ +#define TXQ_NUM 64 +#define RXQ_NUM 128 + +#define PHY_RESET_DELAYS_PROPERTY "hisilicon,phy-reset-delays-us" +#define MAC_RESET_DELAY_PROPERTY "hisilicon,mac-reset-delay-us" +#define MAC_RESET_ASSERT_PERIOD 200000 + +enum phy_reset_delays { + PRE_DELAY, + PULSE, + POST_DELAY, + DELAYS_NUM, +}; + +enum clk_type { + CLK_MAC, + CLK_BUS, + CLK_PHY, + CLK_NUM, +}; + +struct hisi_femac_priv { + void __iomem *port_base; + void __iomem *glb_base; + struct clk *clks[CLK_NUM]; + struct reset_ctl *mac_rst; + struct reset_ctl *phy_rst; + u32 phy_reset_delays[DELAYS_NUM]; + u32 mac_reset_delay; + + struct phy_device *phy; + + u32 link_status; +}; + +static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs) +{ + u32 val; + + val = readl(priv->glb_base + GLB_IRQ_ENA); + writel(val | irqs, priv->glb_base + GLB_IRQ_ENA); +} + +static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, int irqs) +{ + u32 val; + + val = readl(priv->glb_base + GLB_IRQ_ENA); + writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA); +} + +static void hisi_femac_port_init(struct hisi_femac_priv *priv) +{ + u32 val; + + /* MAC gets link status info and phy mode by software config */ + val = MAC_PORTSEL_STAT_CPU; + if (priv->phy->interface == PHY_INTERFACE_MODE_RMII) + val |= MAC_PORTSEL_RMII; + writel(val, priv->port_base + MAC_PORTSEL); + + /*clear all interrupt status */ + writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW); + hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0); + + val = readl(priv->glb_base + GLB_FWCTRL); + val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU); + val |= FWCTRL_FW2CPU_ENA; + writel(val, priv->glb_base + GLB_FWCTRL); + + val = readl(priv->glb_base + GLB_MACTCTRL); + val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA); + writel(val, priv->glb_base + GLB_MACTCTRL); + + val = readl(priv->port_base + MAC_SET); + val &= ~MAX_FRAME_SIZE_MASK; + val |= MAX_FRAME_SIZE; + writel(val, priv->port_base + MAC_SET); + + val = RX_COALESCED_TIMER | + (RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET); + writel(val, priv->port_base + RX_COALESCE_SET); + + val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH; + writel(val, priv->port_base + QLEN_SET); +} + +static void hisi_femac_rx_refill(struct hisi_femac_priv *priv) +{ + int i; + ulong addr; + + for (i = 0; i < HW_RX_FIFO_DEPTH; i++) { + addr = (ulong)net_rx_packets[i]; + writel(addr, priv->port_base + IQ_ADDR); + } +} + +static void hisi_femac_adjust_link(struct udevice *dev) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + struct phy_device *phy = priv->phy; + u32 status = 0; + + if (phy->link) + status |= MAC_PORTSET_LINKED; + if (phy->duplex == DUPLEX_FULL) + status |= MAC_PORTSET_DUPLEX_FULL; + if (phy->speed == SPEED_100) + status |= MAC_PORTSET_SPEED_100M; + + writel(status, priv->port_base + MAC_PORTSET); +} + +static int hisi_femac_port_reset(struct hisi_femac_priv *priv) +{ + u32 val; + + val = readl(priv->glb_base + GLB_SOFT_RESET); + val |= SOFT_RESET_ALL; + writel(val, priv->glb_base + GLB_SOFT_RESET); + + udelay(800); + + val &= ~SOFT_RESET_ALL; + writel(val, priv->glb_base + GLB_SOFT_RESET); + + return 0; +} + +static int hisi_femac_set_hw_mac_addr(struct udevice *dev) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + struct eth_pdata *plat = dev_get_plat(dev); + unsigned char *mac = plat->enetaddr; + u32 reg; + + reg = mac[1] | (mac[0] << 8); + writel(reg, priv->glb_base + GLB_HOSTMAC_H16); + + reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24); + writel(reg, priv->glb_base + GLB_HOSTMAC_L32); + + return 0; +} + +static int hisi_femac_start(struct udevice *dev) +{ + int ret; + struct hisi_femac_priv *priv = dev_get_priv(dev); + + hisi_femac_port_reset(priv); + hisi_femac_set_hw_mac_addr(dev); + hisi_femac_rx_refill(priv); + + ret = phy_startup(priv->phy); + if (ret) + return log_msg_ret("Failed to startup phy", ret); + + if (!priv->phy->link) { + debug("%s: link down\n", __func__); + return -ENODEV; + } + + hisi_femac_adjust_link(dev); + + writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW); + hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK); + + return 0; +} + +static int hisi_femac_send(struct udevice *dev, void *packet, int length) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + ulong addr = (ulong)packet; + int ret; + + // clear previous irq + writel(IRQ_INT_TX_PER_PACKET, priv->glb_base + GLB_IRQ_RAW); + + // flush cache + flush_cache(addr, length + ETH_FCS_LEN); + + // write packet address + writel(addr, priv->port_base + EQ_ADDR); + + // write packet length (and send it) + writel(length + ETH_FCS_LEN, priv->port_base + EQFRM_LEN); + + // wait until FIFO is empty + ret = wait_for_bit_le32(priv->glb_base + GLB_IRQ_RAW, IRQ_INT_TX_PER_PACKET, true, 50, false); + if (ret == -ETIMEDOUT) + return log_msg_ret("FIFO timeout", ret); + + return 0; +} + +static int hisi_femac_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + int val, index, length; + + val = readl(priv->glb_base + GLB_IRQ_RAW); + if (!(val & IRQ_INT_RX_RDY)) + return -EAGAIN; + + val = readl(priv->port_base + IQFRM_DES); + index = (val & RX_FRAME_IN_INDEX_MASK) >> 12; + length = val & RX_FRAME_LEN_MASK; + + // invalidate cache + invalidate_dcache_range((ulong)net_rx_packets[index], (ulong)net_rx_packets[index] + length); + *packetp = net_rx_packets[index]; + + // Tell hardware we will process the packet + writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW); + + return length; +} + +static int hisi_femac_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + ulong addr = (ulong)packet; + + // Tell hardware the packet can be reused + writel(addr, priv->port_base + IQ_ADDR); + + return 0; +} + +static void hisi_femac_stop(struct udevice *dev) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + + // assert internal reset + writel(SOFT_RESET_ALL, priv->glb_base + GLB_SOFT_RESET); +} + +int hisi_femac_of_to_plat(struct udevice *dev) +{ + int ret, i; + struct hisi_femac_priv *priv = dev_get_priv(dev); + static const char * const clk_strs[] = { + [CLK_MAC] = "mac", + [CLK_BUS] = "bus", + [CLK_PHY] = "phy", + }; + + priv->port_base = dev_remap_addr_name(dev, "port"); + if (IS_ERR(priv->port_base)) + return log_msg_ret("Failed to remap port address space", PTR_ERR(priv->port_base)); + + priv->glb_base = dev_remap_addr_name(dev, "glb"); + if (IS_ERR(priv->glb_base)) + return log_msg_ret("Failed to remap global address space", PTR_ERR(priv->glb_base)); + + for (i = 0; i < ARRAY_SIZE(clk_strs); i++) { + priv->clks[i] = devm_clk_get(dev, clk_strs[i]); + if (IS_ERR(priv->clks[i])) { + dev_err(dev, "Error getting clock %s\n", clk_strs[i]); + return log_msg_ret("Failed to get clocks", PTR_ERR(priv->clks[i])); + } + } + + priv->mac_rst = devm_reset_control_get(dev, "mac"); + if (IS_ERR(priv->mac_rst)) + return log_msg_ret("Failed to get MAC reset", PTR_ERR(priv->mac_rst)); + + priv->phy_rst = devm_reset_control_get(dev, "phy"); + if (IS_ERR(priv->phy_rst)) + return log_msg_ret("Failed to get PHY reset", PTR_ERR(priv->phy_rst)); + + ret = dev_read_u32_array(dev, + PHY_RESET_DELAYS_PROPERTY, + priv->phy_reset_delays, + DELAYS_NUM); + if (ret < 0) + return log_msg_ret("Failed to get PHY reset delays", ret); + + priv->mac_reset_delay = dev_read_u32_default(dev, + MAC_RESET_DELAY_PROPERTY, + MAC_RESET_ASSERT_PERIOD); + + return 0; +} + +static int hisi_femac_phy_reset(struct hisi_femac_priv *priv) +{ + struct reset_ctl *rst = priv->phy_rst; + u32 *delays = priv->phy_reset_delays; + int ret; + + // Disable MAC clk before phy reset + ret = clk_disable(priv->clks[CLK_MAC]); + if (ret < 0) + return log_msg_ret("Failed to disable MAC clock", ret); + ret = clk_disable(priv->clks[CLK_BUS]); + if (ret < 0) + return log_msg_ret("Failed to disable bus clock", ret); + + udelay(delays[PRE_DELAY]); + + ret = reset_assert(rst); + if (ret < 0) + return log_msg_ret("Failed to assert reset", ret); + + udelay(delays[PULSE]); + + ret = reset_deassert(rst); + if (ret < 0) + return log_msg_ret("Failed to deassert reset", ret); + + udelay(delays[POST_DELAY]); + + ret = clk_enable(priv->clks[CLK_MAC]); + if (ret < 0) + return log_msg_ret("Failed to enable MAC clock", ret); + ret = clk_enable(priv->clks[CLK_BUS]); + if (ret < 0) + return log_msg_ret("Failed to enable MAC bus clock", ret); + + return 0; +} + +int hisi_femac_probe(struct udevice *dev) +{ + struct hisi_femac_priv *priv = dev_get_priv(dev); + int ret, i; + + // Enable clocks + for (i = 0; i < CLK_NUM; i++) { + ret = clk_prepare_enable(priv->clks[i]); + if (ret < 0) + return log_msg_ret("Failed to enable clks", ret); + } + + // Reset MAC + ret = reset_assert(priv->mac_rst); + if (ret < 0) + return log_msg_ret("Failed to assert MAC reset", ret); + + udelay(priv->mac_reset_delay); + + ret = reset_deassert(priv->mac_rst); + if (ret < 0) + return log_msg_ret("Failed to deassert MAC reset", ret); + + // Reset PHY + ret = hisi_femac_phy_reset(priv); + if (ret < 0) + return log_msg_ret("Failed to reset phy", ret); + + // Connect to PHY + priv->phy = dm_eth_phy_connect(dev); + if (!priv->phy) + return log_msg_ret("Failed to connect to phy", -EINVAL); + + hisi_femac_port_init(priv); + return 0; +} + +static const struct eth_ops hisi_femac_ops = { + .start = hisi_femac_start, + .send = hisi_femac_send, + .recv = hisi_femac_recv, + .free_pkt = hisi_femac_free_pkt, + .stop = hisi_femac_stop, + .write_hwaddr = hisi_femac_set_hw_mac_addr, +}; + +static const struct udevice_id hisi_femac_ids[] = { + {.compatible = "hisilicon,hisi-femac-v1",}, + {.compatible = "hisilicon,hisi-femac-v2",}, + {.compatible = "hisilicon,hi3516cv300-femac",}, + {.compatible = "hisilicon,hi3798mv200-femac",}, + {}, +}; + +U_BOOT_DRIVER(hisi_femac_driver) = { + .name = "eth_hisi_femac", + .id = UCLASS_ETH, + .of_match = of_match_ptr(hisi_femac_ids), + .of_to_plat = hisi_femac_of_to_plat, + .ops = &hisi_femac_ops, + .probe = hisi_femac_probe, + .plat_auto = sizeof(struct eth_pdata), + .priv_auto = sizeof(struct hisi_femac_priv), +}; diff --git a/drivers/net/hifemac_mdio.c b/drivers/net/hifemac_mdio.c new file mode 100644 index 0000000..343c5f3 --- /dev/null +++ b/drivers/net/hifemac_mdio.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hisilicon Fast Ethernet MDIO Bus Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + */ + +#include <dm.h> +#include <clk.h> +#include <miiphy.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#define MDIO_RWCTRL 0x00 +#define MDIO_RO_DATA 0x04 +#define MDIO_WRITE BIT(13) +#define MDIO_RW_FINISH BIT(15) +#define BIT_PHY_ADDR_OFFSET 8 +#define BIT_WR_DATA_OFFSET 16 + +struct hisi_femac_mdio_data { + struct clk *clk; + void __iomem *membase; +}; + +static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) +{ + u32 val; + + return readl_poll_timeout(data->membase + MDIO_RWCTRL, + val, val & MDIO_RW_FINISH, 10000); +} + +static int hisi_femac_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel((addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + return readl(data->membase + MDIO_RO_DATA) & 0xFFFF; +} + +static int hisi_femac_mdio_write(struct udevice *dev, int addr, int devad, int reg, u16 val) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = hisi_femac_mdio_wait_ready(data); + if (ret) + return ret; + + writel(MDIO_WRITE | (val << BIT_WR_DATA_OFFSET) | + (addr << BIT_PHY_ADDR_OFFSET) | reg, + data->membase + MDIO_RWCTRL); + + return hisi_femac_mdio_wait_ready(data); +} + +static int hisi_femac_mdio_of_to_plat(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + data->membase = dev_remap_addr(dev); + if (IS_ERR(data->membase)) { + ret = PTR_ERR(data->membase); + return log_msg_ret("Failed to remap base addr", ret); + } + + // clk is optional + data->clk = devm_clk_get_optional(dev, NULL); + + return 0; +} + +static int hisi_femac_mdio_probe(struct udevice *dev) +{ + struct hisi_femac_mdio_data *data = dev_get_priv(dev); + int ret; + + ret = clk_prepare_enable(data->clk); + if (ret) + return log_msg_ret("Failed to enable clk", ret); + + return 0; +} + +static const struct mdio_ops hisi_femac_mdio_ops = { + .read = hisi_femac_mdio_read, + .write = hisi_femac_mdio_write, +}; + +static const struct udevice_id hisi_femac_mdio_dt_ids[] = { + { .compatible = "hisilicon,hisi-femac-mdio" }, + { } +}; + +U_BOOT_DRIVER(hisi_femac_mdio_driver) = { + .name = "hisi-femac-mdio", + .id = UCLASS_MDIO, + .of_match = hisi_femac_mdio_dt_ids, + .of_to_plat = hisi_femac_mdio_of_to_plat, + .probe = hisi_femac_mdio_probe, + .ops = &hisi_femac_mdio_ops, + .priv_auto = sizeof(struct hisi_femac_mdio_data), +}; diff --git a/drivers/net/mv88e6xxx.c b/drivers/net/mv88e6xxx.c index 64e860e..c073f81 100644 --- a/drivers/net/mv88e6xxx.c +++ b/drivers/net/mv88e6xxx.c @@ -29,6 +29,7 @@ #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/of_extra.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include <miiphy.h> #include <net/dsa.h> @@ -110,20 +111,35 @@ */ #define SMI_BUSY BIT(15) #define SMI_CMD_CLAUSE_22 BIT(12) -#define SMI_CMD_CLAUSE_22_OP_READ (2 << 10) -#define SMI_CMD_CLAUSE_22_OP_WRITE (1 << 10) -#define SMI_CMD_ADDR_SHIFT 5 -#define SMI_CMD_ADDR_MASK 0x1f -#define SMI_CMD_REG_SHIFT 0 -#define SMI_CMD_REG_MASK 0x1f +#define SMI_CMD_OP_MASK GENMASK(11, 10) +#define SMI_CMD_CLAUSE_22_OP_WRITE 0x1 +#define SMI_CMD_CLAUSE_22_OP_READ 0x2 +#define SMI_CMD_CLAUSE_45_OP_WRITE_ADDR 0x0 +#define SMI_CMD_CLAUSE_45_OP_WRITE 0x1 +#define SMI_CMD_CLAUSE_45_OP_READ 0x3 + +#define SMI_CMD_ADDR_MASK GENMASK(9, 5) +#define SMI_CMD_REG_MASK GENMASK(4, 0) #define SMI_CMD_READ(addr, reg) \ - (SMI_BUSY | SMI_CMD_CLAUSE_22 | SMI_CMD_CLAUSE_22_OP_READ) | \ - (((addr) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \ - (((reg) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT) + (SMI_BUSY | SMI_CMD_CLAUSE_22 | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_22_OP_READ)) | \ + (FIELD_PREP(SMI_CMD_ADDR_MASK, addr)) | \ + (FIELD_PREP(SMI_CMD_REG_MASK, reg)) #define SMI_CMD_WRITE(addr, reg) \ - (SMI_BUSY | SMI_CMD_CLAUSE_22 | SMI_CMD_CLAUSE_22_OP_WRITE) | \ - (((addr) & SMI_CMD_ADDR_MASK) << SMI_CMD_ADDR_SHIFT) | \ - (((reg) & SMI_CMD_REG_MASK) << SMI_CMD_REG_SHIFT) + (SMI_BUSY | SMI_CMD_CLAUSE_22 | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_22_OP_WRITE)) | \ + (FIELD_PREP(SMI_CMD_ADDR_MASK, addr)) | \ + (FIELD_PREP(SMI_CMD_REG_MASK, reg)) +#define SMI_CMD_SET_C45_ADDR(phyad, devad) \ + (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_WRITE_ADDR)) | \ + (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \ + (FIELD_PREP(SMI_CMD_REG_MASK, devad)) +#define SMI_CMD_READ_C45(phyad, devad) \ + (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_READ)) | \ + (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \ + (FIELD_PREP(SMI_CMD_REG_MASK, devad)) +#define SMI_CMD_WRITE_C45(phyad, devad) \ + (SMI_BUSY | FIELD_PREP(SMI_CMD_OP_MASK, SMI_CMD_CLAUSE_45_OP_WRITE)) | \ + (FIELD_PREP(SMI_CMD_ADDR_MASK, phyad)) | \ + (FIELD_PREP(SMI_CMD_REG_MASK, devad)) /* ID register values for different switch models */ #define PORT_SWITCH_ID_6020 0x0200 @@ -272,12 +288,37 @@ static int mv88e6xxx_phy_wait(struct udevice *dev) static int mv88e6xxx_phy_read_indirect(struct udevice *dev, int phyad, int devad, int reg) { struct mv88e6xxx_priv *priv = dev_get_priv(dev); + u16 smi_cmd; int res; + if (devad >= 0) { + /* + * For C45 we need to write the register address into the + * PHY Data register first and then call the Write Address + * Register OP in the PHY command register. + */ + res = mv88e6xxx_reg_write(dev, priv->global2, + GLOBAL2_REG_PHY_DATA, + reg); + + res = mv88e6xxx_reg_write(dev, priv->global2, + GLOBAL2_REG_PHY_CMD, + SMI_CMD_SET_C45_ADDR(phyad, devad)); + + /* Wait for busy bit to clear */ + res = mv88e6xxx_phy_wait(dev); + if (res < 0) + return res; + + /* Set the actual C45 or C22 OP-s */ + smi_cmd = SMI_CMD_READ_C45(phyad, devad); + } else + smi_cmd = SMI_CMD_READ(phyad, reg); + /* Issue command to read */ res = mv88e6xxx_reg_write(dev, priv->global2, GLOBAL2_REG_PHY_CMD, - SMI_CMD_READ(phyad, reg)); + smi_cmd); /* Wait for data to be read */ res = mv88e6xxx_phy_wait(dev); @@ -293,8 +334,33 @@ static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad, int devad, int reg, u16 data) { struct mv88e6xxx_priv *priv = dev_get_priv(dev); + u16 smi_cmd; int res; + if (devad >= 0) { + /* + * For C45 we need to write the register address into the + * PHY Data register first and then call the Write Address + * Register OP in the PHY command register. + */ + res = mv88e6xxx_reg_write(dev, priv->global2, + GLOBAL2_REG_PHY_DATA, + reg); + + res = mv88e6xxx_reg_write(dev, priv->global2, + GLOBAL2_REG_PHY_CMD, + SMI_CMD_SET_C45_ADDR(phyad, devad)); + + /* Wait for busy bit to clear */ + res = mv88e6xxx_phy_wait(dev); + if (res < 0) + return res; + + /* Set the actual C45 or C22 OP-s */ + smi_cmd = SMI_CMD_WRITE_C45(phyad, devad); + } else + smi_cmd = SMI_CMD_WRITE(phyad, reg); + /* Set the data to write */ res = mv88e6xxx_reg_write(dev, priv->global2, GLOBAL2_REG_PHY_DATA, data); @@ -303,7 +369,7 @@ static int mv88e6xxx_phy_write_indirect(struct udevice *dev, int phyad, /* Issue the write command */ res = mv88e6xxx_reg_write(dev, priv->global2, GLOBAL2_REG_PHY_CMD, - SMI_CMD_WRITE(phyad, reg)); + smi_cmd); if (res < 0) return res; diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 8d32d73..f9d4782 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -81,7 +81,10 @@ /* RGMIIDCTL bits */ #define DP83869_RGMII_TX_CLK_DELAY_SHIFT 4 -#define DP83869_CLK_DELAY_DEF 7 +#define DP83869_CLK_DELAY_STEP 250 +#define DP83869_CLK_DELAY_MIN 250 +#define DP83869_CLK_DELAY_MAX 4000 +#define DP83869_CLK_DELAY_DEFAULT 2000 /* CFG2 bits */ #define MII_DP83869_CFG2_SPEEDOPT_10EN 0x0040 @@ -157,10 +160,6 @@ static int dp83869_config_port_mirroring(struct phy_device *phydev) return 0; } -static const int dp83869_internal_delay[] = {250, 500, 750, 1000, 1250, 1500, - 1750, 2000, 2250, 2500, 2750, 3000, - 3250, 3500, 3750, 4000}; - static int dp83869_set_strapped_mode(struct phy_device *phydev) { struct dp83869_private *dp83869 = phydev->priv; @@ -183,7 +182,6 @@ static int dp83869_set_strapped_mode(struct phy_device *phydev) static int dp83869_of_init(struct phy_device *phydev) { struct dp83869_private * const dp83869 = phydev->priv; - const int delay_entries = ARRAY_SIZE(dp83869_internal_delay); int ret; ofnode node; @@ -238,32 +236,45 @@ static int dp83869_of_init(struct phy_device *phydev) dp83869->tx_fifo_depth = ofnode_read_s32_default(node, "tx-fifo-depth", DP83869_PHYCR_FIFO_DEPTH_4_B_NIB); + /* Internal clock delay values can be configured in steps of + * 250ps (0.25ns). The register field for clock delay is 4-bits wide, + * the values range from 0b0000 for 0.25ns to 0b1111 for 4ns. + */ + /* 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) { - dp83869->rx_int_delay = ofnode_read_u32_default(node, "rx-internal-delay-ps", - DP83869_CLK_DELAY_DEF); - if (dp83869->rx_int_delay > delay_entries) { - dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF; - pr_debug("rx-internal-delay-ps not set/invalid, default to %ups\n", - dp83869_internal_delay[dp83869->rx_int_delay]); + dp83869->rx_int_delay = ofnode_read_u32_default(node, + "rx-internal-delay-ps", DP83869_CLK_DELAY_DEFAULT); + if (dp83869->rx_int_delay > DP83869_CLK_DELAY_MAX || + dp83869->rx_int_delay < DP83869_CLK_DELAY_MIN || + dp83869->rx_int_delay % DP83869_CLK_DELAY_STEP) { + dp83869->rx_int_delay = DP83869_CLK_DELAY_DEFAULT; + pr_warn("rx-internal-delay-ps not set/invalid, default" + " to %ups\n", DP83869_CLK_DELAY_DEFAULT); } - dp83869->rx_int_delay = dp83869_internal_delay[dp83869->rx_int_delay]; + dp83869->rx_int_delay = + (dp83869->rx_int_delay - DP83869_CLK_DELAY_STEP) + / DP83869_CLK_DELAY_STEP; } - /* TX delay *must* be specified if internal delay of RX is used. */ + /* TX delay *must* be specified if internal delay of TX is used. */ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { - dp83869->tx_int_delay = ofnode_read_u32_default(node, "tx-internal-delay-ps", - DP83869_CLK_DELAY_DEF); - if (dp83869->tx_int_delay > delay_entries) { - dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF; - pr_debug("tx-internal-delay-ps not set/invalid, default to %ups\n", - dp83869_internal_delay[dp83869->tx_int_delay]); + dp83869->tx_int_delay = ofnode_read_u32_default(node, + "tx-internal-delay-ps", DP83869_CLK_DELAY_DEFAULT); + if (dp83869->tx_int_delay > DP83869_CLK_DELAY_MAX || + dp83869->tx_int_delay < DP83869_CLK_DELAY_MIN || + dp83869->tx_int_delay % DP83869_CLK_DELAY_STEP) { + dp83869->tx_int_delay = DP83869_CLK_DELAY_DEFAULT; + pr_warn("tx-internal-delay-ps not set/invalid, default" + " to %ups\n", DP83869_CLK_DELAY_DEFAULT); } - dp83869->tx_int_delay = dp83869_internal_delay[dp83869->tx_int_delay]; + dp83869->tx_int_delay = + (dp83869->tx_int_delay - DP83869_CLK_DELAY_STEP) + / DP83869_CLK_DELAY_STEP; } return 0; diff --git a/include/net.h b/include/net.h index e254df7..e63a946 100644 --- a/include/net.h +++ b/include/net.h @@ -16,6 +16,7 @@ #include <asm/cache.h> #include <asm/byteorder.h> /* for nton* / ntoh* stuff */ #include <env.h> +#include <hexdump.h> #include <log.h> #include <time.h> #include <linux/if_ether.h> @@ -29,6 +30,7 @@ struct udevice; #define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */ #define DEBUG_NET_PKT 0 /* Packets on info on the network at large */ #define DEBUG_INT_STATE 0 /* Internal network state changes */ +#define DEBUG_NET_PKT_TRACE 0 /* Trace all packet data */ /* * The number of receive packet buffers, and the required packet buffer @@ -640,6 +642,8 @@ uchar * net_get_async_tx_pkt_buf(void); /* Transmit a packet */ static inline void net_send_packet(uchar *pkt, int len) { + if (DEBUG_NET_PKT_TRACE) + print_hex_dump_bytes("tx: ", DUMP_PREFIX_OFFSET, pkt, len); /* Currently no way to return errors from eth_send() */ (void) eth_send(pkt, len); } diff --git a/net/bootp.c b/net/bootp.c index 7b0f45e..6800290 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -26,6 +26,7 @@ #ifdef CONFIG_BOOTP_RANDOM_DELAY #include "net_rand.h" #endif +#include <malloc.h> #define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */ @@ -601,6 +602,10 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip, *e++ = 42; *cnt += 1; #endif + if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) { + *e++ = 209; /* PXELINUX Config File */ + *cnt += 1; + } /* no options, so back up to avoid sending an empty request list */ if (*cnt == 0) e -= 2; @@ -909,6 +914,22 @@ static void dhcp_process_options(uchar *popt, uchar *end) net_boot_file_name[size] = 0; } break; + case 209: /* PXELINUX Config File */ + if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) { + /* In case it has already been allocated when get DHCP Offer packet, + * free first to avoid memory leak. + */ + if (pxelinux_configfile) + free(pxelinux_configfile); + + pxelinux_configfile = (char *)malloc((oplen + 1) * sizeof(char)); + + if (pxelinux_configfile) + strlcpy(pxelinux_configfile, popt + 2, oplen + 1); + else + printf("Error: Failed to allocate pxelinux_configfile\n"); + } + break; default: #if defined(CONFIG_BOOTP_VENDOREX) if (dhcp_vendorex_proc(popt)) diff --git a/net/dhcpv6.c b/net/dhcpv6.c index 73a1067..4aea779 100644 --- a/net/dhcpv6.c +++ b/net/dhcpv6.c @@ -304,7 +304,7 @@ static void dhcp6_parse_ia_options(struct dhcp6_option_hdr *ia_ptr, uchar *ia_op static void dhcp6_parse_options(uchar *rx_pkt, unsigned int len) { uchar *option_ptr; - int sol_max_rt_sec, option_len; + int sol_max_rt_sec, option_len, param_len_1; char *s, *e; struct dhcp6_option_hdr *option_hdr; @@ -390,14 +390,23 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned int len) case DHCP6_OPTION_OPT_BOOTFILE_PARAM: if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION)) { debug("DHCP6_OPTION_OPT_BOOTFILE_PARAM FOUND\n"); + /* if CONFIG_DHCP6_PXE_DHCP_OPTION is set the PXE config file path + * is contained in the first OPT_BOOTFILE_PARAM argument + */ + param_len_1 = ntohs(*((u16 *)option_ptr)); + option_ptr += sizeof(u16); + if (param_len_1 + sizeof(u16) > option_len) { + debug("Invalid BOOTFILE_PARAM param_len_1. Skipping\n"); + break; + } if (pxelinux_configfile) free(pxelinux_configfile); - pxelinux_configfile = (char *)malloc((option_len + 1) * + pxelinux_configfile = (char *)malloc((param_len_1 + 1) * sizeof(char)); if (pxelinux_configfile) - strlcpy(pxelinux_configfile, option_ptr, option_len + 1); + strlcpy(pxelinux_configfile, option_ptr, param_len_1 + 1); else printf("Error: Failed to allocate pxelinux_configfile\n"); diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 4311f3f..3d0ec91 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -562,10 +562,14 @@ static int eth_post_probe(struct udevice *dev) /* Check if the device has a valid MAC address in device tree */ if (!eth_dev_get_mac_address(dev, pdata->enetaddr) || !is_valid_ethaddr(pdata->enetaddr)) { - source = "ROM"; /* Check if the device has a MAC address in ROM */ - if (eth_get_ops(dev)->read_rom_hwaddr) - eth_get_ops(dev)->read_rom_hwaddr(dev); + if (eth_get_ops(dev)->read_rom_hwaddr) { + int ret; + + ret = eth_get_ops(dev)->read_rom_hwaddr(dev); + if (!ret) + source = "ROM"; + } } eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr); @@ -594,7 +598,7 @@ static int eth_post_probe(struct udevice *dev) eth_env_set_enetaddr_by_index("eth", dev_seq(dev), pdata->enetaddr); #else - printf("\nError: %s address not set.\n", + printf("\nError: %s No valid MAC address found.\n", dev->name); return -EINVAL; #endif @@ -1201,6 +1201,9 @@ void net_process_received_packet(uchar *in_packet, int len) ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid; debug_cond(DEBUG_NET_PKT, "packet received\n"); + if (DEBUG_NET_PKT_TRACE) + print_hex_dump_bytes("rx: ", DUMP_PREFIX_OFFSET, in_packet, + len); #if defined(CONFIG_CMD_PCAP) pcap_post(in_packet, len, false); |