summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig14
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/dwc_eth_qos.c8
-rw-r--r--drivers/net/dwc_eth_qos_rockchip.c292
-rw-r--r--drivers/net/phy/Kconfig34
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/air_en8811h.c783
-rw-r--r--drivers/net/sandbox-lwip.c85
-rw-r--r--drivers/net/sandbox.c250
9 files changed, 464 insertions, 1004 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a0a7890bd26..4434d364777 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -48,7 +48,6 @@ config DM_DSA
bool "Enable Driver Model for DSA switches"
depends on DM_MDIO
depends on PHY_FIXED
- depends on !NET_LWIP
help
Enable driver model for DSA switches
@@ -358,7 +357,7 @@ config ESSEDMA
config ETH_SANDBOX
depends on SANDBOX
- depends on NET
+ depends on NET || NET_LWIP
default y
bool "Sandbox: Mocked Ethernet driver"
help
@@ -367,17 +366,6 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
-config ETH_SANDBOX_LWIP
- depends on SANDBOX
- depends on NET_LWIP
- default y
- bool "Sandbox: Mocked Ethernet driver (for NET_LWIP)"
- help
- This driver is meant as a replacement for ETH_SANDBOX when
- the network stack is NET_LWIP rather than NET. It currently
- does nothing, i.e. it drops the sent packets and never receives
- data.
-
config ETH_SANDBOX_RAW
depends on SANDBOX
depends on NET
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3244d39036d..67bba3a8536 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -41,7 +41,6 @@ obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o
obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
-obj-$(CONFIG_ETH_SANDBOX_LWIP) += sandbox-lwip.o
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
obj-$(CONFIG_FMAN_ENET) += fm/
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index b4ec3614696..b1bc422f791 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -1612,10 +1612,18 @@ static const struct udevice_id eqos_ids[] = {
#endif
#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ROCKCHIP)
{
+ .compatible = "rockchip,rk3528-gmac",
+ .data = (ulong)&eqos_rockchip_config
+ },
+ {
.compatible = "rockchip,rk3568-gmac",
.data = (ulong)&eqos_rockchip_config
},
{
+ .compatible = "rockchip,rk3576-gmac",
+ .data = (ulong)&eqos_rockchip_config
+ },
+ {
.compatible = "rockchip,rk3588-gmac",
.data = (ulong)&eqos_rockchip_config
},
diff --git a/drivers/net/dwc_eth_qos_rockchip.c b/drivers/net/dwc_eth_qos_rockchip.c
index f3a0f63003e..d646d3ebac8 100644
--- a/drivers/net/dwc_eth_qos_rockchip.c
+++ b/drivers/net/dwc_eth_qos_rockchip.c
@@ -50,6 +50,132 @@ struct rockchip_platform_data {
(((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \
((rx) ? soc##_GMAC_RXCLK_DLY_ENABLE : soc##_GMAC_RXCLK_DLY_DISABLE))
+#define RK3528_VO_GRF_GMAC_CON 0x0018
+#define RK3528_VPU_GRF_GMAC_CON5 0x0018
+#define RK3528_VPU_GRF_GMAC_CON6 0x001c
+
+#define RK3528_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3528_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3528_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+#define RK3528_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+
+#define RK3528_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8)
+#define RK3528_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0)
+
+#define RK3528_GMAC0_PHY_INTF_SEL_RMII GRF_BIT(1)
+#define RK3528_GMAC1_PHY_INTF_SEL_RGMII GRF_CLR_BIT(8)
+#define RK3528_GMAC1_PHY_INTF_SEL_RMII GRF_BIT(8)
+
+#define RK3528_GMAC1_CLK_SELECT_CRU GRF_CLR_BIT(12)
+#define RK3528_GMAC1_CLK_SELECT_IO GRF_BIT(12)
+
+#define RK3528_GMAC0_CLK_RMII_DIV2 GRF_BIT(3)
+#define RK3528_GMAC0_CLK_RMII_DIV20 GRF_CLR_BIT(3)
+#define RK3528_GMAC1_CLK_RMII_DIV2 GRF_BIT(10)
+#define RK3528_GMAC1_CLK_RMII_DIV20 GRF_CLR_BIT(10)
+
+#define RK3528_GMAC1_CLK_RGMII_DIV1 (GRF_CLR_BIT(11) | GRF_CLR_BIT(10))
+#define RK3528_GMAC1_CLK_RGMII_DIV5 (GRF_BIT(11) | GRF_BIT(10))
+#define RK3528_GMAC1_CLK_RGMII_DIV50 (GRF_BIT(11) | GRF_CLR_BIT(10))
+
+#define RK3528_GMAC0_CLK_RMII_GATE GRF_BIT(2)
+#define RK3528_GMAC0_CLK_RMII_NOGATE GRF_CLR_BIT(2)
+#define RK3528_GMAC1_CLK_RMII_GATE GRF_BIT(9)
+#define RK3528_GMAC1_CLK_RMII_NOGATE GRF_CLR_BIT(9)
+
+static int rk3528_set_to_rgmii(struct udevice *dev,
+ int tx_delay, int rx_delay)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5,
+ RK3528_GMAC1_PHY_INTF_SEL_RGMII);
+
+ regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5,
+ DELAY_ENABLE(RK3528, tx_delay, rx_delay));
+
+ regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON6,
+ RK3528_GMAC_CLK_RX_DL_CFG(rx_delay) |
+ RK3528_GMAC_CLK_TX_DL_CFG(tx_delay));
+
+ return 0;
+}
+
+static int rk3528_set_to_rmii(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ if (data->id == 1)
+ regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5,
+ RK3528_GMAC1_PHY_INTF_SEL_RMII);
+ else
+ regmap_write(data->grf, RK3528_VO_GRF_GMAC_CON,
+ RK3528_GMAC0_PHY_INTF_SEL_RMII |
+ RK3528_GMAC0_CLK_RMII_DIV2);
+
+ return 0;
+}
+
+static int rk3528_set_gmac_speed(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val, reg;
+
+ switch (eqos->phy->speed) {
+ case SPEED_10:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = data->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV20 :
+ RK3528_GMAC0_CLK_RMII_DIV20;
+ else
+ val = RK3528_GMAC1_CLK_RGMII_DIV50;
+ break;
+ case SPEED_100:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = data->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV2 :
+ RK3528_GMAC0_CLK_RMII_DIV2;
+ else
+ val = RK3528_GMAC1_CLK_RGMII_DIV5;
+ break;
+ case SPEED_1000:
+ if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII)
+ val = RK3528_GMAC1_CLK_RGMII_DIV1;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ reg = data->id == 1 ? RK3528_VPU_GRF_GMAC_CON5 :
+ RK3528_VO_GRF_GMAC_CON;
+ regmap_write(data->grf, reg, val);
+
+ return 0;
+}
+
+static void rk3528_set_clock_selection(struct udevice *dev, bool enable)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val;
+
+ if (data->id == 1) {
+ val = data->clock_input ? RK3528_GMAC1_CLK_SELECT_IO :
+ RK3528_GMAC1_CLK_SELECT_CRU;
+ val |= enable ? RK3528_GMAC1_CLK_RMII_NOGATE :
+ RK3528_GMAC1_CLK_RMII_GATE;
+ regmap_write(data->grf, RK3528_VPU_GRF_GMAC_CON5, val);
+ } else {
+ val = enable ? RK3528_GMAC0_CLK_RMII_NOGATE :
+ RK3528_GMAC0_CLK_RMII_GATE;
+ regmap_write(data->grf, RK3528_VO_GRF_GMAC_CON, val);
+ }
+}
+
#define RK3568_GRF_GMAC0_CON0 0x0380
#define RK3568_GRF_GMAC0_CON1 0x0384
#define RK3568_GRF_GMAC1_CON0 0x0388
@@ -134,6 +260,145 @@ static int rk3568_set_gmac_speed(struct udevice *dev)
return 0;
}
+/* VCCIO0_1_3_IOC */
+#define RK3576_VCCIO0_1_3_IOC_CON2 0x6408
+#define RK3576_VCCIO0_1_3_IOC_CON3 0x640c
+#define RK3576_VCCIO0_1_3_IOC_CON4 0x6410
+#define RK3576_VCCIO0_1_3_IOC_CON5 0x6414
+
+#define RK3576_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define RK3576_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define RK3576_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
+#define RK3576_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
+
+#define RK3576_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
+#define RK3576_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+/* SDGMAC_GRF */
+#define RK3576_GRF_GMAC_CON0 0x0020
+#define RK3576_GRF_GMAC_CON1 0x0024
+
+#define RK3576_GMAC_RMII_MODE GRF_BIT(3)
+#define RK3576_GMAC_RGMII_MODE GRF_CLR_BIT(3)
+
+#define RK3576_GMAC_CLK_SELECT_IO GRF_BIT(7)
+#define RK3576_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(7)
+
+#define RK3576_GMAC_CLK_RMII_DIV2 GRF_BIT(5)
+#define RK3576_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(5)
+
+#define RK3576_GMAC_CLK_RGMII_DIV1 \
+ (GRF_CLR_BIT(6) | GRF_CLR_BIT(5))
+#define RK3576_GMAC_CLK_RGMII_DIV5 \
+ (GRF_BIT(6) | GRF_BIT(5))
+#define RK3576_GMAC_CLK_RGMII_DIV50 \
+ (GRF_BIT(6) | GRF_CLR_BIT(5))
+
+#define RK3576_GMAC_CLK_RMII_GATE GRF_BIT(4)
+#define RK3576_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(4)
+
+static int rk3576_set_to_rgmii(struct udevice *dev,
+ int tx_delay, int rx_delay)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 offset_con;
+
+ offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 :
+ RK3576_GRF_GMAC_CON0;
+
+ regmap_write(data->grf, offset_con, RK3576_GMAC_RGMII_MODE);
+
+ offset_con = data->id == 1 ? RK3576_VCCIO0_1_3_IOC_CON4 :
+ RK3576_VCCIO0_1_3_IOC_CON2;
+
+ /* m0 && m1 delay enabled */
+ regmap_write(data->php_grf, offset_con,
+ DELAY_ENABLE(RK3576, tx_delay, rx_delay));
+ regmap_write(data->php_grf, offset_con + 0x4,
+ DELAY_ENABLE(RK3576, tx_delay, rx_delay));
+
+ /* m0 && m1 delay value */
+ regmap_write(data->php_grf, offset_con,
+ RK3576_GMAC_CLK_TX_DL_CFG(tx_delay) |
+ RK3576_GMAC_CLK_RX_DL_CFG(rx_delay));
+ regmap_write(data->php_grf, offset_con + 0x4,
+ RK3576_GMAC_CLK_TX_DL_CFG(tx_delay) |
+ RK3576_GMAC_CLK_RX_DL_CFG(rx_delay));
+
+ return 0;
+}
+
+static int rk3576_set_to_rmii(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 offset_con;
+
+ offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 :
+ RK3576_GRF_GMAC_CON0;
+
+ regmap_write(data->grf, offset_con, RK3576_GMAC_RMII_MODE);
+
+ return 0;
+}
+
+static int rk3576_set_gmac_speed(struct udevice *dev)
+{
+ struct eqos_priv *eqos = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+ u32 val = 0, offset_con;
+
+ switch (eqos->phy->speed) {
+ case SPEED_10:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = RK3576_GMAC_CLK_RMII_DIV20;
+ else
+ val = RK3576_GMAC_CLK_RGMII_DIV50;
+ break;
+ case SPEED_100:
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
+ val = RK3576_GMAC_CLK_RMII_DIV2;
+ else
+ val = RK3576_GMAC_CLK_RGMII_DIV5;
+ break;
+ case SPEED_1000:
+ if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII)
+ val = RK3576_GMAC_CLK_RGMII_DIV1;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 :
+ RK3576_GRF_GMAC_CON0;
+
+ regmap_write(data->grf, offset_con, val);
+
+ return 0;
+}
+
+static void rk3576_set_clock_selection(struct udevice *dev, bool enable)
+{
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct rockchip_platform_data *data = pdata->priv_pdata;
+
+ u32 val = data->clock_input ? RK3576_GMAC_CLK_SELECT_IO :
+ RK3576_GMAC_CLK_SELECT_CRU;
+ u32 offset_con;
+
+ val |= enable ? RK3576_GMAC_CLK_RMII_NOGATE :
+ RK3576_GMAC_CLK_RMII_GATE;
+
+ offset_con = data->id == 1 ? RK3576_GRF_GMAC_CON1 :
+ RK3576_GRF_GMAC_CON0;
+
+ regmap_write(data->grf, offset_con, val);
+}
+
#define RK3588_DELAY_ENABLE(id, tx, rx) \
(((tx) ? RK3588_GMAC_TXCLK_DLY_ENABLE(id) : RK3588_GMAC_TXCLK_DLY_DISABLE(id)) | \
((rx) ? RK3588_GMAC_RXCLK_DLY_ENABLE(id) : RK3588_GMAC_RXCLK_DLY_DISABLE(id)))
@@ -270,6 +535,18 @@ static void rk3588_set_clock_selection(struct udevice *dev, bool enable)
static const struct rk_gmac_ops rk_gmac_ops[] = {
{
+ .compatible = "rockchip,rk3528-gmac",
+ .set_to_rgmii = rk3528_set_to_rgmii,
+ .set_to_rmii = rk3528_set_to_rmii,
+ .set_gmac_speed = rk3528_set_gmac_speed,
+ .set_clock_selection = rk3528_set_clock_selection,
+ .regs = {
+ 0xffbd0000, /* gmac0 */
+ 0xffbe0000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+ },
+ {
.compatible = "rockchip,rk3568-gmac",
.set_to_rgmii = rk3568_set_to_rgmii,
.set_to_rmii = rk3568_set_to_rmii,
@@ -281,6 +558,18 @@ static const struct rk_gmac_ops rk_gmac_ops[] = {
},
},
{
+ .compatible = "rockchip,rk3576-gmac",
+ .set_to_rgmii = rk3576_set_to_rgmii,
+ .set_to_rmii = rk3576_set_to_rmii,
+ .set_gmac_speed = rk3576_set_gmac_speed,
+ .set_clock_selection = rk3576_set_clock_selection,
+ .regs = {
+ 0x2a220000, /* gmac0 */
+ 0x2a230000, /* gmac1 */
+ 0x0, /* sentinel */
+ },
+ },
+ {
.compatible = "rockchip,rk3588-gmac",
.set_to_rgmii = rk3588_set_to_rgmii,
.set_to_rmii = rk3588_set_to_rmii,
@@ -357,7 +646,8 @@ static int eqos_probe_resources_rk(struct udevice *dev)
goto err_free;
}
- if (device_is_compatible(dev, "rockchip,rk3588-gmac")) {
+ if (device_is_compatible(dev, "rockchip,rk3588-gmac") ||
+ device_is_compatible(dev, "rockchip,rk3576-gmac")) {
data->php_grf =
syscon_regmap_lookup_by_phandle(dev, "rockchip,php-grf");
if (IS_ERR(data->php_grf)) {
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 5b4cf30b0a3..3132718e4f8 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -79,40 +79,6 @@ config PHY_ADIN
help
Add support for configuring RGMII on Analog Devices ADIN PHYs.
-menuconfig PHY_AIROHA
- bool "Airoha Ethernet PHYs support"
-
-config PHY_AIROHA_EN8811H
- bool "Airoha Ethernet EN8811H support"
- depends on PHY_AIROHA
- help
- AIROHA EN8811H supported.
-
-choice
- prompt "Location of the Airoha PHY firmware"
- default PHY_AIROHA_FW_IN_MMC
- depends on PHY_AIROHA_EN8811H
-
-config PHY_AIROHA_FW_IN_MMC
- bool "Airoha firmware in MMC boot1 partition"
-
-endchoice
-
-config AIROHA_FW_ADDR
- hex "Airoha Firmware Address"
- depends on PHY_AIROHA_EN8811H
- default 0x0
-
-config AIROHA_MD32_DM_SIZE
- hex "Airoha Firmware MD32 DM Size"
- depends on PHY_AIROHA_EN8811H
- default 0x4000
-
-config AIROHA_MD32_DSP_SIZE
- hex "Airoha Firmware MD32 DSP Size"
- depends on PHY_AIROHA_EN8811H
- default 0x20000
-
menuconfig PHY_AQUANTIA
bool "Aquantia Ethernet PHYs support"
select PHY_GIGE
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 87dee3c15b9..2487f366e1c 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o
obj-$(CONFIG_PHYLIB) += phy.o
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
obj-$(CONFIG_PHY_ADIN) += adin.o
-obj-$(CONFIG_PHY_AIROHA_EN8811H) += air_en8811h.o
obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
deleted file mode 100644
index 96bb24418a0..00000000000
--- a/drivers/net/phy/air_en8811h.c
+++ /dev/null
@@ -1,783 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Driver for the Airoha EN8811H 2.5 Gigabit PHY.
- *
- * Limitations of the EN8811H:
- * - Only full duplex supported
- * - Forced speed (AN off) is not supported by hardware (100Mbps)
- *
- * Source originated from linux air_en8811h.c
- *
- * Copyright (C) 2025 Airoha Technology Corp.
- */
-#include <phy.h>
-#include <errno.h>
-#include <malloc.h>
-#include <asm/unaligned.h>
-#include <linux/iopoll.h>
-#include <dm/device_compat.h>
-#include <linux/bitops.h>
-#include <mmc.h>
-
-#define EN8811H_PHY_ID 0x03a2a411
-
-#define AIR_FW_ADDR_DM 0x00000000
-#define AIR_FW_ADDR_DSP 0x00100000
-
-#define EN8811H_MD32_DM_SIZE 0x4000
-#define EN8811H_MD32_DSP_SIZE 0x20000
-
- #define EN8811H_FW_CTRL_1 0x0f0018
- #define EN8811H_FW_CTRL_1_START 0x0
- #define EN8811H_FW_CTRL_1_FINISH 0x1
- #define EN8811H_FW_CTRL_2 0x800000
- #define EN8811H_FW_CTRL_2_LOADING BIT(11)
-
- /* MII Registers */
- #define AIR_AUX_CTRL_STATUS 0x1d
- #define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
- #define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
- #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
- #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
-
-#define AIR_EXT_PAGE_ACCESS 0x1f
-#define AIR_PHY_PAGE_STANDARD 0x0000
-#define AIR_PHY_PAGE_EXTENDED_4 0x0004
-
-/* MII Registers Page 4*/
-#define AIR_BPBUS_MODE 0x10
-#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
-#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
-#define AIR_BPBUS_WR_ADDR_HIGH 0x11
-#define AIR_BPBUS_WR_ADDR_LOW 0x12
-#define AIR_BPBUS_WR_DATA_HIGH 0x13
-#define AIR_BPBUS_WR_DATA_LOW 0x14
-#define AIR_BPBUS_RD_ADDR_HIGH 0x15
-#define AIR_BPBUS_RD_ADDR_LOW 0x16
-#define AIR_BPBUS_RD_DATA_HIGH 0x17
-#define AIR_BPBUS_RD_DATA_LOW 0x18
-
-/* Registers on MDIO_MMD_VEND1 */
-#define EN8811H_PHY_FW_STATUS 0x8009
-#define EN8811H_PHY_READY 0x02
-
-/* Registers on MDIO_MMD_VEND2 */
-#define AIR_PHY_LED_BCR 0x021
-#define AIR_PHY_LED_BCR_MODE_MASK GENMASK(1, 0)
-#define AIR_PHY_LED_BCR_TIME_TEST BIT(2)
-#define AIR_PHY_LED_BCR_CLK_EN BIT(3)
-#define AIR_PHY_LED_BCR_EXT_CTRL BIT(15)
-
-#define AIR_PHY_LED_DUR_ON 0x022
-
-#define AIR_PHY_LED_DUR_BLINK 0x023
-
-#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
-#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
-#define AIR_PHY_LED_ON_LINK1000 BIT(0)
-#define AIR_PHY_LED_ON_LINK100 BIT(1)
-#define AIR_PHY_LED_ON_LINK10 BIT(2)
-#define AIR_PHY_LED_ON_LINKDOWN BIT(3)
-#define AIR_PHY_LED_ON_FDX BIT(4) /* Full duplex */
-#define AIR_PHY_LED_ON_HDX BIT(5) /* Half duplex */
-#define AIR_PHY_LED_ON_FORCE_ON BIT(6)
-#define AIR_PHY_LED_ON_LINK2500 BIT(8)
-#define AIR_PHY_LED_ON_POLARITY BIT(14)
-#define AIR_PHY_LED_ON_ENABLE BIT(15)
-
-#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
-#define AIR_PHY_LED_BLINK_1000TX BIT(0)
-#define AIR_PHY_LED_BLINK_1000RX BIT(1)
-#define AIR_PHY_LED_BLINK_100TX BIT(2)
-#define AIR_PHY_LED_BLINK_100RX BIT(3)
-#define AIR_PHY_LED_BLINK_10TX BIT(4)
-#define AIR_PHY_LED_BLINK_10RX BIT(5)
-#define AIR_PHY_LED_BLINK_COLLISION BIT(6)
-#define AIR_PHY_LED_BLINK_RX_CRC_ERR BIT(7)
-#define AIR_PHY_LED_BLINK_RX_IDLE_ERR BIT(8)
-#define AIR_PHY_LED_BLINK_FORCE_BLINK BIT(9)
-#define AIR_PHY_LED_BLINK_2500TX BIT(10)
-#define AIR_PHY_LED_BLINK_2500RX BIT(11)
-
-#define EN8811H_FW_VERSION 0x3b3c
-
-#define EN8811H_POLARITY 0xca0f8
-#define EN8811H_POLARITY_TX_NORMAL BIT(0)
-#define EN8811H_POLARITY_RX_REVERSE BIT(1)
-
-#define EN8811H_CLK_CGM 0xcf958
-#define EN8811H_CLK_CGM_CKO BIT(26)
-#define EN8811H_HWTRAP1 0xcf914
-#define EN8811H_HWTRAP1_CKO BIT(12)
-
-#define air_upper_16_bits(n) ((u16)((n) >> 16))
-#define air_lower_16_bits(n) ((u16)((n) & 0xffff))
-
-/* Led definitions */
-#define EN8811H_LED_COUNT 3
-
-/* Default LED setup:
- * GPIO5 <-> LED0 On: Link detected
- * GPIO4 <-> LED1 On: Link detected at 2500 and 1000 Mbps
- * GPIO3 <-> LED2 On: Link detected at 2500 and 100 Mbps
- */
-#define AIR_DEFAULT_TRIGGER_LED0 (AIR_PHY_LED_ON_LINK2500 | \
- AIR_PHY_LED_ON_LINK1000 | \
- AIR_PHY_LED_ON_LINK100)
-#define AIR_DEFAULT_TRIGGER_LED1 (AIR_PHY_LED_ON_LINK2500 | \
- AIR_PHY_LED_ON_LINK1000 | \
- AIR_PHY_LED_BLINK_2500TX | \
- AIR_PHY_LED_BLINK_2500RX | \
- AIR_PHY_LED_BLINK_1000TX | \
- AIR_PHY_LED_BLINK_1000RX)
-#define AIR_DEFAULT_TRIGGER_LED2 (AIR_PHY_LED_ON_LINK2500 | \
- AIR_PHY_LED_ON_LINK100 | \
- AIR_PHY_LED_BLINK_2500TX | \
- AIR_PHY_LED_BLINK_2500RX | \
- AIR_PHY_LED_BLINK_100TX | \
- AIR_PHY_LED_BLINK_100RX)
-
-struct led {
- unsigned long rules;
-};
-
-enum {
- AIR_PHY_LED_DUR_BLINK_32MS,
- AIR_PHY_LED_DUR_BLINK_64MS,
- AIR_PHY_LED_DUR_BLINK_128MS,
- AIR_PHY_LED_DUR_BLINK_256MS,
- AIR_PHY_LED_DUR_BLINK_512MS,
- AIR_PHY_LED_DUR_BLINK_1024MS,
-};
-
-enum {
- AIR_LED_DISABLE,
- AIR_LED_ENABLE,
-};
-
-enum {
- AIR_ACTIVE_LOW,
- AIR_ACTIVE_HIGH,
-};
-
-enum {
- AIR_LED_MODE_DISABLE,
- AIR_LED_MODE_USER_DEFINE,
-};
-
-#define AIR_PHY_LED_DUR_UNIT 781
-#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
-
-struct en8811h_priv {
- int firmware_version;
- bool mcu_needs_restart;
- struct led led[EN8811H_LED_COUNT];
-};
-
-static int air_phy_read_page(struct phy_device *phydev)
-{
- return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS);
-}
-
-static int air_phy_write_page(struct phy_device *phydev, int page)
-{
- return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page);
-}
-
-int air_phy_select_page(struct phy_device *phydev, int page)
-{
- int ret, oldpage;
-
- oldpage = air_phy_read_page(phydev);
- if (oldpage < 0)
- return oldpage;
-
- if (oldpage != page) {
- ret = air_phy_write_page(phydev, page);
- if (ret < 0)
- return ret;
- }
-
- return oldpage;
-}
-
-int air_phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
-{
- int r;
-
- if (oldpage >= 0) {
- r = air_phy_write_page(phydev, oldpage);
-
- if (ret >= 0 && r < 0)
- ret = r;
- } else {
- ret = oldpage;
- }
-
- return ret;
-}
-
-static int air_buckpbus_reg_write(struct phy_device *phydev,
- u32 pbus_address, u32 pbus_data)
-{
- int ret, saved_page;
-
- saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
- air_upper_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
- air_lower_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
- air_upper_16_bits(pbus_data));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
- air_lower_16_bits(pbus_data));
- if (ret < 0)
- goto restore_page;
- }
-
-restore_page:
- if (ret < 0)
- printf("%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
-
- return air_phy_restore_page(phydev, saved_page, ret);
-}
-
-static int air_buckpbus_reg_read(struct phy_device *phydev,
- u32 pbus_address, u32 *pbus_data)
-{
- int pbus_data_low, pbus_data_high;
- int ret = 0, saved_page;
-
- saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
- air_upper_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
- air_lower_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0) {
- ret = pbus_data_high;
- goto restore_page;
- }
-
- pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0) {
- ret = pbus_data_low;
- goto restore_page;
- }
-
- *pbus_data = pbus_data_low | (pbus_data_high << 16);
- }
-
-restore_page:
- if (ret < 0)
- printf("%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
-
- return air_phy_restore_page(phydev, saved_page, ret);
-}
-
-static int air_buckpbus_reg_modify(struct phy_device *phydev,
- u32 pbus_address, u32 mask, u32 set)
-{
- int pbus_data_low, pbus_data_high;
- u32 pbus_data_old, pbus_data_new;
- int ret = 0, saved_page;
-
- saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH,
- air_upper_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW,
- air_lower_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0)
- return pbus_data_high;
-
- pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0)
- return pbus_data_low;
-
- pbus_data_old = pbus_data_low | (pbus_data_high << 16);
- pbus_data_new = (pbus_data_old & ~mask) | set;
- if (pbus_data_new == pbus_data_old)
- return 0;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
- air_upper_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
- air_lower_16_bits(pbus_address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH,
- air_upper_16_bits(pbus_data_new));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW,
- air_lower_16_bits(pbus_data_new));
- if (ret < 0)
- goto restore_page;
- }
-
-restore_page:
- if (ret < 0)
- printf("%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
-
- return air_phy_restore_page(phydev, saved_page, ret);
-}
-
-static int air_write_buf(struct phy_device *phydev, unsigned long address,
- unsigned long array_size, const unsigned char *buffer)
-{
- unsigned int offset;
- int ret, saved_page;
- u16 val;
-
- saved_page = air_phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_INCR);
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH,
- air_upper_16_bits(address));
- if (ret < 0)
- goto restore_page;
-
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW,
- air_lower_16_bits(address));
- if (ret < 0)
- goto restore_page;
-
- for (offset = 0; offset < array_size; offset += 4) {
- val = get_unaligned_le16(&buffer[offset + 2]);
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, val);
- if (ret < 0)
- goto restore_page;
-
- val = get_unaligned_le16(&buffer[offset]);
- ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, val);
- if (ret < 0)
- goto restore_page;
- }
- }
-
-restore_page:
- if (ret < 0)
- printf("%s 0x%08lx failed: %d\n", __func__,
- address, ret);
-
- return air_phy_restore_page(phydev, saved_page, ret);
-}
-
-__weak ulong *en8811h_get_fw_addr(void)
-{
- return (ulong *)CONFIG_AIROHA_FW_ADDR;
-}
-
-static int en8811h_wait_mcu_ready(struct phy_device *phydev)
-{
- int ret, reg_value;
-
- /* Because of mdio-lock, may have to wait for multiple loads */
- ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
- EN8811H_PHY_FW_STATUS, reg_value,
- reg_value == EN8811H_PHY_READY,
- 20000, 7500000, true);
- if (ret) {
- printf("MCU not ready: 0x%x\n", reg_value);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int en8811h_load_firmware(struct phy_device *phydev)
-{
- int ret;
- char *addr = NULL;
- struct en8811h_priv *priv = phydev->priv;
- int dev = CONFIG_SYS_MMC_ENV_DEV;
- u32 cnt = (CONFIG_AIROHA_MD32_DM_SIZE +
- CONFIG_AIROHA_MD32_DSP_SIZE) / 512;
- ulong airoha_fw_addr = (ulong)en8811h_get_fw_addr();
- u32 blk = airoha_fw_addr / 512;
-
- addr = malloc(CONFIG_AIROHA_MD32_DM_SIZE + CONFIG_AIROHA_MD32_DSP_SIZE);
- if (!addr) {
- puts("cannot allocated buffer for firmware.\n");
- return -ENOMEM;
- }
-
- if (IS_ENABLED(CONFIG_PHY_AIROHA_FW_IN_MMC)) {
- struct mmc *mmc = find_mmc_device(dev);
-
- if (!mmc) {
- puts("Failed to find MMC device for Airoha ucode\n");
- goto en8811h_load_firmware_out;
- }
-
- printf("MMC read: dev # %u, block # %u, count %u ...\n",
- dev, blk, cnt);
-
- if (mmc_init(mmc)) {
- puts("initializing MMC device failed.\n");
- goto en8811h_load_firmware_out;
- }
-
- ret = mmc_set_part_conf(mmc, 1, 2, 2);
- if (ret) {
- puts("cannot access eMMC boot1 hw partition.\n");
- goto en8811h_load_firmware_out;
- }
-
- (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
-
- mmc_set_part_conf(mmc, 1, 1, 0);
-
- } else {
- puts("EN8811H firmware loading not implemented");
- free(addr);
- addr = NULL;
- return -EOPNOTSUPP;
- }
-
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_START);
- if (ret < 0)
- return ret;
-
- ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
- EN8811H_FW_CTRL_2_LOADING,
- EN8811H_FW_CTRL_2_LOADING);
- if (ret < 0)
- return ret;
-
- ret = air_write_buf(phydev, AIR_FW_ADDR_DM, CONFIG_AIROHA_MD32_DM_SIZE, addr);
- if (ret < 0)
- goto en8811h_load_firmware_out;
-
- ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, CONFIG_AIROHA_MD32_DSP_SIZE,
- addr + CONFIG_AIROHA_MD32_DM_SIZE);
- if (ret < 0)
- goto en8811h_load_firmware_out;
-
- ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
- EN8811H_FW_CTRL_2_LOADING, 0);
- if (ret < 0)
- return ret;
-
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_FINISH);
- if (ret < 0)
- return ret;
-
- ret = en8811h_wait_mcu_ready(phydev);
-
- air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
- &priv->firmware_version);
- printf("MD32 firmware version: %08x\n",
- priv->firmware_version);
-
-en8811h_load_firmware_out:
- free(addr);
- if (ret < 0)
- printf("Firmware loading failed: %d\n", ret);
-
- return ret;
-}
-
-static int en8811h_restart_mcu(struct phy_device *phydev)
-{
- int ret;
-
- ret = phy_write_mmd(phydev, 0x1e, 0x8009, 0x0);
- if (ret < 0)
- return ret;
-
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_START);
- if (ret < 0)
- return ret;
-
- return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_FINISH);
-}
-
-static int air_led_hw_control_set(struct phy_device *phydev,
- u8 index, unsigned long rules)
-{
- struct en8811h_priv *priv = phydev->priv;
- u16 on = 0, blink = 0;
- int ret;
-
- if (index >= EN8811H_LED_COUNT)
- return -EINVAL;
-
- on |= rules & (AIR_PHY_LED_ON_LINK100 |
- AIR_PHY_LED_ON_LINK1000 |
- AIR_PHY_LED_ON_LINK2500);
-
- blink |= rules & (AIR_PHY_LED_BLINK_100TX |
- AIR_PHY_LED_BLINK_100RX |
- AIR_PHY_LED_BLINK_1000TX |
- AIR_PHY_LED_BLINK_1000RX |
- AIR_PHY_LED_BLINK_2500TX |
- AIR_PHY_LED_BLINK_2500RX);
-
- if (blink || on) {
- on &= ~AIR_PHY_LED_ON_FORCE_ON;
- blink &= ~AIR_PHY_LED_BLINK_FORCE_BLINK;
- } else {
- priv->led[index].rules = 0;
- }
-
- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_ON(index),
- AIR_PHY_LED_ON_MASK, on);
- if (ret < 0)
- return ret;
-
- return phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BLINK(index),
- blink);
-}
-
-static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
-{
- int val = 0;
- int err;
-
- if (index >= EN8811H_LED_COUNT)
- return -EINVAL;
-
- if (state == AIR_LED_ENABLE)
- val |= AIR_PHY_LED_ON_ENABLE;
- else
- val &= ~AIR_PHY_LED_ON_ENABLE;
-
- if (pol == AIR_ACTIVE_HIGH)
- val |= AIR_PHY_LED_ON_POLARITY;
- else
- val &= ~AIR_PHY_LED_ON_POLARITY;
-
- err = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_ON(index), val);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int air_leds_init(struct phy_device *phydev, int num, int dur, int mode)
-{
- int ret, i;
- struct en8811h_priv *priv = phydev->priv;
-
- ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_BLINK, dur);
- if (ret < 0)
- return ret;
-
- ret = phy_write_mmd(phydev, 0x1f, AIR_PHY_LED_DUR_ON, dur >> 1);
- if (ret < 0)
- return ret;
-
- switch (mode) {
- case AIR_LED_MODE_DISABLE:
- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
- AIR_PHY_LED_BCR_EXT_CTRL |
- AIR_PHY_LED_BCR_MODE_MASK, 0);
- break;
- case AIR_LED_MODE_USER_DEFINE:
- ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_BCR,
- AIR_PHY_LED_BCR_EXT_CTRL |
- AIR_PHY_LED_BCR_CLK_EN,
- AIR_PHY_LED_BCR_EXT_CTRL |
- AIR_PHY_LED_BCR_CLK_EN);
- if (ret < 0)
- return ret;
- break;
- default:
- printf("LED mode %d is not supported\n", mode);
- return -EINVAL;
- }
-
- for (i = 0; i < num; ++i) {
- ret = air_led_init(phydev, i, AIR_LED_ENABLE, AIR_ACTIVE_HIGH);
- if (ret < 0) {
- printf("LED%d init failed: %d\n", i, ret);
- return ret;
- }
- air_led_hw_control_set(phydev, i, priv->led[i].rules);
- }
-
- return 0;
-}
-
-static int en8811h_config(struct phy_device *phydev)
-{
- ofnode node = phy_get_ofnode(phydev);
- struct en8811h_priv *priv = phydev->priv;
- int ret = 0;
- u32 pbus_value = 0;
-
- /* If restart happened in .probe(), no need to restart now */
- if (priv->mcu_needs_restart) {
- ret = en8811h_restart_mcu(phydev);
- if (ret < 0)
- return ret;
- } else {
- ret = en8811h_load_firmware(phydev);
- if (ret) {
- printf("Load firmware fail.\n");
- return ret;
- }
- /* Next calls to .config() mcu needs to restart */
- priv->mcu_needs_restart = true;
- }
-
- ret = phy_write_mmd(phydev, 0x1e, 0x800c, 0x0);
- ret |= phy_write_mmd(phydev, 0x1e, 0x800d, 0x0);
- ret |= phy_write_mmd(phydev, 0x1e, 0x800e, 0x1101);
- ret |= phy_write_mmd(phydev, 0x1e, 0x800f, 0x0002);
- if (ret < 0)
- return ret;
-
- /* Serdes polarity */
- pbus_value = 0;
- if (ofnode_read_bool(node, "airoha,pnswap-rx"))
- pbus_value |= EN8811H_POLARITY_RX_REVERSE;
- else
- pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
- if (ofnode_read_bool(node, "airoha,pnswap-tx"))
- pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
- else
- pbus_value |= EN8811H_POLARITY_TX_NORMAL;
- ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
- EN8811H_POLARITY_RX_REVERSE |
- EN8811H_POLARITY_TX_NORMAL, pbus_value);
- if (ret < 0)
- return ret;
-
- ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
- AIR_LED_MODE_USER_DEFINE);
- if (ret < 0) {
- printf("Failed to disable leds: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static int en8811h_parse_status(struct phy_device *phydev)
-{
- int ret = 0, reg_value;
-
- phydev->duplex = DUPLEX_FULL;
-
- reg_value = phy_read(phydev, MDIO_DEVAD_NONE, AIR_AUX_CTRL_STATUS);
- if (reg_value < 0)
- return reg_value;
-
- switch (reg_value & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
- case AIR_AUX_CTRL_STATUS_SPEED_2500:
- phydev->speed = SPEED_2500;
- break;
- case AIR_AUX_CTRL_STATUS_SPEED_1000:
- phydev->speed = SPEED_1000;
- break;
- case AIR_AUX_CTRL_STATUS_SPEED_100:
- phydev->speed = SPEED_100;
- break;
- default:
- printf("Auto-neg error, defaulting to 100M/FD\n");
- phydev->speed = SPEED_100;
- break;
- }
-
- return ret;
-}
-
-static int en8811h_startup(struct phy_device *phydev)
-{
- int ret = 0;
-
- ret = genphy_update_link(phydev);
- if (ret)
- return ret;
-
- return en8811h_parse_status(phydev);
-}
-
-static int en8811h_probe(struct phy_device *phydev)
-{
- struct en8811h_priv *priv;
-
- priv = malloc(sizeof(*priv));
- if (!priv)
- return -ENOMEM;
- memset(priv, 0, sizeof(*priv));
-
- priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
- priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
- priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
-
- /* mcu has just restarted after firmware load */
- priv->mcu_needs_restart = false;
-
- phydev->priv = priv;
-
- return 0;
-}
-
-U_BOOT_PHY_DRIVER(en8811h) = {
- .name = "Airoha EN8811H",
- .uid = EN8811H_PHY_ID,
- .mask = 0x0ffffff0,
- .config = &en8811h_config,
- .probe = &en8811h_probe,
- .startup = &en8811h_startup,
- .shutdown = &genphy_shutdown,
-};
diff --git a/drivers/net/sandbox-lwip.c b/drivers/net/sandbox-lwip.c
deleted file mode 100644
index 3721033c310..00000000000
--- a/drivers/net/sandbox-lwip.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2015 National Instruments
- *
- * (C) Copyright 2015
- * Joe Hershberger <joe.hershberger@ni.com>
- */
-
-#include <dm.h>
-#include <log.h>
-#include <malloc.h>
-#include <net.h>
-#include <asm/eth.h>
-#include <asm/global_data.h>
-#include <asm/test.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static int sb_lwip_eth_start(struct udevice *dev)
-{
- debug("eth_sandbox_lwip: Start\n");
-
- return 0;
-}
-
-static int sb_lwip_eth_send(struct udevice *dev, void *packet, int length)
-{
- debug("eth_sandbox_lwip: Send packet %d\n", length);
-
- return -ENOTSUPP;
-}
-
-static int sb_lwip_eth_recv(struct udevice *dev, int flags, uchar **packetp)
-{
- return -EAGAIN;
-}
-
-static int sb_lwip_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
-{
- return 0;
-}
-
-static void sb_lwip_eth_stop(struct udevice *dev)
-{
-}
-
-static int sb_lwip_eth_write_hwaddr(struct udevice *dev)
-{
- return 0;
-}
-
-static const struct eth_ops sb_eth_ops = {
- .start = sb_lwip_eth_start,
- .send = sb_lwip_eth_send,
- .recv = sb_lwip_eth_recv,
- .free_pkt = sb_lwip_eth_free_pkt,
- .stop = sb_lwip_eth_stop,
- .write_hwaddr = sb_lwip_eth_write_hwaddr,
-};
-
-static int sb_lwip_eth_remove(struct udevice *dev)
-{
- return 0;
-}
-
-static int sb_lwip_eth_of_to_plat(struct udevice *dev)
-{
- return 0;
-}
-
-static const struct udevice_id sb_eth_ids[] = {
- { .compatible = "sandbox,eth" },
- { }
-};
-
-U_BOOT_DRIVER(eth_sandbox) = {
- .name = "eth_lwip_sandbox",
- .id = UCLASS_ETH,
- .of_match = sb_eth_ids,
- .of_to_plat = sb_lwip_eth_of_to_plat,
- .remove = sb_lwip_eth_remove,
- .ops = &sb_eth_ops,
- .priv_auto = 0,
- .plat_auto = sizeof(struct eth_pdata),
-};
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index fe3627db6e3..2011fd31f41 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -9,13 +9,84 @@
#include <dm.h>
#include <log.h>
#include <malloc.h>
-#include <net.h>
#include <asm/eth.h>
#include <asm/global_data.h>
#include <asm/test.h>
+#include <asm/types.h>
+
+/*
+ * Structure definitions for network protocols. Since this file is used for
+ * both NET and NET_LWIP, and given that the two network stacks do have
+ * conflicting types (for instance struct icmp_hdr), it is on purpose that the
+ * structures are defined locally with minimal dependencies -- <asm/types.h> is
+ * included for the bit types and that's it.
+ */
+
+#define ETHADDR_LEN 6
+#define IP4_LEN 4
+
+struct ethhdr {
+ u8 dst[ETHADDR_LEN];
+ u8 src[ETHADDR_LEN];
+ u16 protlen;
+} __attribute__((packed));
+
+#define ETHHDR_SIZE (sizeof(struct ethhdr))
+
+struct arphdr {
+ u16 htype;
+ u16 ptype;
+ u8 hlen;
+ u8 plen;
+ u16 op;
+} __attribute__((packed));
+
+#define ARPHDR_SIZE (sizeof(struct arphdr))
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+struct arpdata {
+ u8 sha[ETHADDR_LEN];
+ u32 spa;
+ u8 tha[ETHADDR_LEN];
+ u32 tpa;
+} __attribute__((packed));
+
+#define ARPDATA_SIZE (sizeof(struct arpdata))
+
+struct iphdr {
+ u8 hl_v;
+ u8 tos;
+ u16 len;
+ u16 id;
+ u16 off;
+ u8 ttl;
+ u8 prot;
+ u16 sum;
+ u32 src;
+ u32 dst;
+} __attribute__((packed));
+
+#define IPHDR_SIZE (sizeof(struct iphdr))
+
+struct icmphdr {
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u16 id;
+ u16 sequence;
+} __attribute__((packed));
+
+#define ICMPHDR_SIZE (sizeof(struct icmphdr))
+
+#define ICMP_ECHO_REQUEST 8
+#define ICMP_ECHO_REPLY 0
+#define IPPROTO_ICMP 1
DECLARE_GLOBAL_DATA_PTR;
+static const u8 null_ethaddr[6];
static bool skip_timeout;
/*
@@ -59,17 +130,19 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet,
unsigned int len)
{
struct eth_sandbox_priv *priv = dev_get_priv(dev);
- struct ethernet_hdr *eth = packet;
- struct arp_hdr *arp;
- struct ethernet_hdr *eth_recv;
- struct arp_hdr *arp_recv;
-
- if (ntohs(eth->et_protlen) != PROT_ARP)
+ struct ethhdr *eth = packet;
+ struct arphdr *arp;
+ struct arpdata *arpd;
+ struct ethhdr *eth_recv;
+ struct arphdr *arp_recv;
+ struct arpdata *arp_recvd;
+
+ if (ntohs(eth->protlen) != PROT_ARP)
return -EAGAIN;
- arp = packet + ETHER_HDR_SIZE;
+ arp = packet + ETHHDR_SIZE;
- if (ntohs(arp->ar_op) != ARPOP_REQUEST)
+ if (ntohs(arp->op) != ARP_REQUEST)
return -EAGAIN;
/* Don't allow the buffer to overrun */
@@ -77,27 +150,29 @@ int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet,
return 0;
/* store this as the assumed IP of the fake host */
- priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
+ arpd = (struct arpdata *)(arp + 1);
+ priv->fake_host_ipaddr.s_addr = arpd->tpa;
/* Formulate a fake response */
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
- memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
- memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
- eth_recv->et_protlen = htons(PROT_ARP);
-
- arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
- arp_recv->ar_hrd = htons(ARP_ETHER);
- arp_recv->ar_pro = htons(PROT_IP);
- arp_recv->ar_hln = ARP_HLEN;
- arp_recv->ar_pln = ARP_PLEN;
- arp_recv->ar_op = htons(ARPOP_REPLY);
- memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
- net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
- memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
- net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
-
- priv->recv_packet_length[priv->recv_packets] =
- ETHER_HDR_SIZE + ARP_HDR_SIZE;
+ memcpy(eth_recv->dst, eth->src, ETHADDR_LEN);
+ memcpy(eth_recv->src, priv->fake_host_hwaddr, ETHADDR_LEN);
+ eth_recv->protlen = htons(PROT_ARP);
+
+ arp_recv = (void *)eth_recv + ETHHDR_SIZE;
+ arp_recv->htype = htons(ARP_ETHER);
+ arp_recv->ptype = htons(PROT_IP);
+ arp_recv->hlen = ETHADDR_LEN;
+ arp_recv->plen = IP4_LEN;
+ arp_recv->op = htons(ARP_REPLY);
+ arp_recvd = (struct arpdata *)(arp_recv + 1);
+ memcpy(&arp_recvd->sha, priv->fake_host_hwaddr, ETHADDR_LEN);
+ arp_recvd->spa = priv->fake_host_ipaddr.s_addr;
+ memcpy(&arp_recvd->tha, &arpd->sha, ETHADDR_LEN);
+ arp_recvd->tpa = arpd->spa;
+
+ priv->recv_packet_length[priv->recv_packets] = ETHHDR_SIZE +
+ ARPHDR_SIZE + ARPDATA_SIZE;
++priv->recv_packets;
return 0;
@@ -114,22 +189,22 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
unsigned int len)
{
struct eth_sandbox_priv *priv = dev_get_priv(dev);
- struct ethernet_hdr *eth = packet;
- struct ip_udp_hdr *ip;
- struct icmp_hdr *icmp;
- struct ethernet_hdr *eth_recv;
- struct ip_udp_hdr *ipr;
- struct icmp_hdr *icmpr;
-
- if (ntohs(eth->et_protlen) != PROT_IP)
+ struct ethhdr *eth = packet;
+ struct iphdr *ip;
+ struct icmphdr *icmp;
+ struct ethhdr *eth_recv;
+ struct iphdr *ipr;
+ struct icmphdr *icmpr;
+
+ if (ntohs(eth->protlen) != PROT_IP)
return -EAGAIN;
- ip = packet + ETHER_HDR_SIZE;
+ ip = packet + ETHHDR_SIZE;
- if (ip->ip_p != IPPROTO_ICMP)
+ if (ip->prot != IPPROTO_ICMP)
return -EAGAIN;
- icmp = (struct icmp_hdr *)&ip->udp_src;
+ icmp = (struct icmphdr *)(ip + 1);
if (icmp->type != ICMP_ECHO_REQUEST)
return -EAGAIN;
@@ -141,19 +216,19 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
/* reply to the ping */
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
memcpy(eth_recv, packet, len);
- ipr = (void *)eth_recv + ETHER_HDR_SIZE;
- icmpr = (struct icmp_hdr *)&ipr->udp_src;
- memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
- memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
- ipr->ip_sum = 0;
- ipr->ip_off = 0;
- net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
- net_write_ip((void *)&ipr->ip_src, priv->fake_host_ipaddr);
- ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
+ ipr = (void *)eth_recv + ETHHDR_SIZE;
+ icmpr = (struct icmphdr *)(ipr + 1);
+ memcpy(eth_recv->dst, eth->src, ETHADDR_LEN);
+ memcpy(eth_recv->src, priv->fake_host_hwaddr, ETHADDR_LEN);
+ ipr->sum = 0;
+ ipr->off = 0;
+ ipr->dst = ip->src;
+ ipr->src = priv->fake_host_ipaddr.s_addr;
+ ipr->sum = compute_ip_checksum(ipr, IPHDR_SIZE);
icmpr->type = ICMP_ECHO_REPLY;
icmpr->checksum = 0;
- icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
+ icmpr->checksum = compute_ip_checksum(icmpr, ICMPHDR_SIZE);
priv->recv_packet_length[priv->recv_packets] = len;
++priv->recv_packets;
@@ -171,8 +246,9 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
int sandbox_eth_recv_arp_req(struct udevice *dev)
{
struct eth_sandbox_priv *priv = dev_get_priv(dev);
- struct ethernet_hdr *eth_recv;
- struct arp_hdr *arp_recv;
+ struct ethhdr *eth_recv;
+ struct arphdr *arp_recv;
+ struct arpdata *arp_recvd;
/* Don't allow the buffer to overrun */
if (priv->recv_packets >= PKTBUFSRX)
@@ -180,23 +256,24 @@ int sandbox_eth_recv_arp_req(struct udevice *dev)
/* Formulate a fake request */
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
- memcpy(eth_recv->et_dest, net_bcast_ethaddr, ARP_HLEN);
- memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
- eth_recv->et_protlen = htons(PROT_ARP);
-
- arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
- arp_recv->ar_hrd = htons(ARP_ETHER);
- arp_recv->ar_pro = htons(PROT_IP);
- arp_recv->ar_hln = ARP_HLEN;
- arp_recv->ar_pln = ARP_PLEN;
- arp_recv->ar_op = htons(ARPOP_REQUEST);
- memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
- net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
- memcpy(&arp_recv->ar_tha, net_null_ethaddr, ARP_HLEN);
- net_write_ip(&arp_recv->ar_tpa, net_ip);
+ memcpy(eth_recv->dst, net_bcast_ethaddr, ETHADDR_LEN);
+ memcpy(eth_recv->src, priv->fake_host_hwaddr, ETHADDR_LEN);
+ eth_recv->protlen = htons(PROT_ARP);
+
+ arp_recv = (void *)eth_recv + ETHHDR_SIZE;
+ arp_recv->htype = htons(ARP_ETHER);
+ arp_recv->ptype = htons(PROT_IP);
+ arp_recv->hlen = ETHADDR_LEN;
+ arp_recv->plen = IP4_LEN;
+ arp_recv->op = htons(ARP_REQUEST);
+ arp_recvd = (struct arpdata *)(arp_recv + 1);
+ memcpy(&arp_recvd->sha, priv->fake_host_hwaddr, ETHADDR_LEN);
+ arp_recvd->spa = priv->fake_host_ipaddr.s_addr;
+ memcpy(&arp_recvd->tha, null_ethaddr, ETHADDR_LEN);
+ arp_recvd->tpa = net_ip.s_addr;
priv->recv_packet_length[priv->recv_packets] =
- ETHER_HDR_SIZE + ARP_HDR_SIZE;
+ ETHHDR_SIZE + ARPHDR_SIZE + ARPDATA_SIZE;
++priv->recv_packets;
return 0;
@@ -212,9 +289,10 @@ int sandbox_eth_recv_arp_req(struct udevice *dev)
int sandbox_eth_recv_ping_req(struct udevice *dev)
{
struct eth_sandbox_priv *priv = dev_get_priv(dev);
- struct ethernet_hdr *eth_recv;
- struct ip_udp_hdr *ipr;
- struct icmp_hdr *icmpr;
+ struct eth_pdata *pdata = dev_get_plat(dev);
+ struct ethhdr *eth_recv;
+ struct iphdr *ipr;
+ struct icmphdr *icmpr;
/* Don't allow the buffer to overrun */
if (priv->recv_packets >= PKTBUFSRX)
@@ -223,31 +301,31 @@ int sandbox_eth_recv_ping_req(struct udevice *dev)
/* Formulate a fake ping */
eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
- memcpy(eth_recv->et_dest, net_ethaddr, ARP_HLEN);
- memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
- eth_recv->et_protlen = htons(PROT_IP);
+ memcpy(eth_recv->dst, pdata->enetaddr, ETHADDR_LEN);
+ memcpy(eth_recv->src, priv->fake_host_hwaddr, ETHADDR_LEN);
+ eth_recv->protlen = htons(PROT_IP);
- ipr = (void *)eth_recv + ETHER_HDR_SIZE;
- ipr->ip_hl_v = 0x45;
- ipr->ip_len = htons(IP_ICMP_HDR_SIZE);
- ipr->ip_off = htons(IP_FLAGS_DFRAG);
- ipr->ip_p = IPPROTO_ICMP;
- ipr->ip_sum = 0;
- net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr);
- net_write_ip(&ipr->ip_dst, net_ip);
- ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
+ ipr = (void *)eth_recv + ETHHDR_SIZE;
+ ipr->hl_v = 0x45;
+ ipr->len = htons(IPHDR_SIZE + ICMPHDR_SIZE);
+ ipr->off = htons(IP_FLAGS_DFRAG);
+ ipr->prot = IPPROTO_ICMP;
+ ipr->sum = 0;
+ ipr->src = priv->fake_host_ipaddr.s_addr;
+ ipr->dst = net_ip.s_addr;
+ ipr->sum = compute_ip_checksum(ipr, IPHDR_SIZE);
- icmpr = (struct icmp_hdr *)&ipr->udp_src;
+ icmpr = (struct icmphdr *)(ipr + 1);
icmpr->type = ICMP_ECHO_REQUEST;
icmpr->code = 0;
icmpr->checksum = 0;
- icmpr->un.echo.id = 0;
- icmpr->un.echo.sequence = htons(1);
- icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
+ icmpr->id = 0;
+ icmpr->sequence = htons(1);
+ icmpr->checksum = compute_ip_checksum(icmpr, ICMPHDR_SIZE);
priv->recv_packet_length[priv->recv_packets] =
- ETHER_HDR_SIZE + IP_ICMP_HDR_SIZE;
+ ETHHDR_SIZE + IPHDR_SIZE + ICMPHDR_SIZE;
++priv->recv_packets;
return 0;
@@ -398,7 +476,7 @@ static int sb_eth_write_hwaddr(struct udevice *dev)
debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
pdata->enetaddr);
- memcpy(priv->fake_host_hwaddr, pdata->enetaddr, ARP_HLEN);
+ memcpy(priv->fake_host_hwaddr, pdata->enetaddr, ETHADDR_LEN);
return 0;
}