diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 8 | ||||
-rw-r--r-- | drivers/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 33 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos.h | 3 | ||||
-rw-r--r-- | drivers/net/dwc_eth_qos_rockchip.c | 531 | ||||
-rw-r--r-- | drivers/net/fsl-mc/mc.c | 110 | ||||
-rw-r--r-- | drivers/net/phy/xilinx_phy.c | 5 | ||||
-rw-r--r-- | drivers/net/sni_netsec.c | 50 | ||||
-rw-r--r-- | drivers/net/sun8i_emac.c | 7 | ||||
-rw-r--r-- | drivers/net/sunxi_emac.c | 38 | ||||
-rw-r--r-- | drivers/net/zynq_gem.c | 73 |
11 files changed, 793 insertions, 66 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 0ed39a61e4d..29304fd7775 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -225,6 +225,14 @@ config DWC_ETH_QOS_IMX The Synopsys Designware Ethernet QOS IP block with the specific configuration used in IMX soc. +config DWC_ETH_QOS_ROCKCHIP + bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs" + depends on DWC_ETH_QOS + select DM_ETH_PHY + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in Rockchip SoCs. + config DWC_ETH_QOS_STM32 bool "Synopsys DWC Ethernet QOS device support for STM32" depends on DWC_ETH_QOS diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d4af253b6f2..1d444f5b4a6 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o +obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o obj-$(CONFIG_E1000) += e1000.o diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9b1a9e69bf8..18466cfe257 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -812,6 +812,7 @@ static int eqos_start(struct udevice *dev) if (!eqos->phy) { pr_err("phy_connect() failed"); + ret = -ENODEV; goto err_stop_resets; } @@ -839,6 +840,7 @@ static int eqos_start(struct udevice *dev) if (!eqos->phy->link) { pr_err("No link"); + ret = -EAGAIN; goto err_shutdown_phy; } @@ -1192,14 +1194,12 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) struct eqos_desc *rx_desc; int length; - debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); - rx_desc = eqos_get_desc(eqos, eqos->rx_desc_idx, true); eqos->config->ops->eqos_inval_desc(rx_desc); - if (rx_desc->des3 & EQOS_DESC3_OWN) { - debug("%s: RX packet not available\n", __func__); + if (rx_desc->des3 & EQOS_DESC3_OWN) return -EAGAIN; - } + + debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); *packetp = eqos->rx_dma_buf + (eqos->rx_desc_idx * EQOS_MAX_PACKET_SIZE); @@ -1315,22 +1315,12 @@ static int eqos_probe_resources_core(struct udevice *dev) } debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); - eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); - if (!eqos->rx_pkt) { - debug("%s: malloc(rx_pkt) failed\n", __func__); - ret = -ENOMEM; - goto err_free_rx_dma_buf; - } - debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt); - eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf, EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX); debug("%s: OK\n", __func__); return 0; -err_free_rx_dma_buf: - free(eqos->rx_dma_buf); err_free_tx_dma_buf: free(eqos->tx_dma_buf); err_free_descs: @@ -1349,7 +1339,6 @@ static int eqos_remove_resources_core(struct udevice *dev) debug("%s(dev=%p):\n", __func__, dev); - free(eqos->rx_pkt); free(eqos->rx_dma_buf); free(eqos->tx_dma_buf); eqos_free_descs(eqos->rx_descs); @@ -1719,7 +1708,16 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_imx_config }, #endif - +#if IS_ENABLED(CONFIG_DWC_ETH_QOS_ROCKCHIP) + { + .compatible = "rockchip,rk3568-gmac", + .data = (ulong)&eqos_rockchip_config + }, + { + .compatible = "rockchip,rk3588-gmac", + .data = (ulong)&eqos_rockchip_config + }, +#endif #if IS_ENABLED(CONFIG_DWC_ETH_QOS_QCOM) { .compatible = "qcom,qcs404-ethqos", @@ -1732,7 +1730,6 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_jh7110_config }, #endif - { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index a6b719af809..e3222e1e17e 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -82,6 +82,7 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 +#define EQOS_MAC_MDIO_ADDRESS_CR_100_150 1 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 #define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) @@ -273,7 +274,6 @@ struct eqos_priv { unsigned int desc_per_cacheline; void *tx_dma_buf; void *rx_dma_buf; - void *rx_pkt; bool started; bool reg_access_ok; bool clk_ck_enabled; @@ -288,5 +288,6 @@ void eqos_flush_buffer_generic(void *buf, size_t size); int eqos_null_ops(struct udevice *dev); extern struct eqos_config eqos_imx_config; +extern struct eqos_config eqos_rockchip_config; extern struct eqos_config eqos_qcom_config; extern struct eqos_config eqos_jh7110_config; diff --git a/drivers/net/dwc_eth_qos_rockchip.c b/drivers/net/dwc_eth_qos_rockchip.c new file mode 100644 index 00000000000..834307a4477 --- /dev/null +++ b/drivers/net/dwc_eth_qos_rockchip.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright Contributors to the U-Boot project. + * + * rk_gmac_ops ported from linux drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c + * + * Ported code is intentionally left as close as possible with linux counter + * part in order to simplify future porting of fixes and support for other SoCs. + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <net.h> +#include <phy.h> +#include <regmap.h> +#include <reset.h> +#include <syscon.h> +#include <asm/gpio.h> +#include <linux/delay.h> + +#include "dwc_eth_qos.h" + +struct rk_gmac_ops { + const char *compatible; + int (*set_to_rgmii)(struct udevice *dev, + int tx_delay, int rx_delay); + int (*set_to_rmii)(struct udevice *dev); + int (*set_gmac_speed)(struct udevice *dev); + void (*set_clock_selection)(struct udevice *dev, bool enable); + u32 regs[3]; +}; + +struct rockchip_platform_data { + struct reset_ctl_bulk resets; + const struct rk_gmac_ops *ops; + int id; + bool clock_input; + struct regmap *grf; + struct regmap *php_grf; +}; + +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +#define GRF_BIT(nr) (BIT(nr) | BIT((nr) + 16)) +#define GRF_CLR_BIT(nr) (BIT((nr) + 16)) + +#define RK3568_GRF_GMAC0_CON0 0x0380 +#define RK3568_GRF_GMAC0_CON1 0x0384 +#define RK3568_GRF_GMAC1_CON0 0x0388 +#define RK3568_GRF_GMAC1_CON1 0x038c + +/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */ +#define RK3568_GMAC_PHY_INTF_SEL_RGMII \ + (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) +#define RK3568_GMAC_PHY_INTF_SEL_RMII \ + (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3) +#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) +#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1) +#define RK3568_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(1) +#define RK3568_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0) +#define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0) + +/* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */ +#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) +#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) + +static int rk3568_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 con0, con1; + + con0 = (data->id == 1) ? RK3568_GRF_GMAC1_CON0 : + RK3568_GRF_GMAC0_CON0; + con1 = (data->id == 1) ? RK3568_GRF_GMAC1_CON1 : + RK3568_GRF_GMAC0_CON1; + + regmap_write(data->grf, con0, + RK3568_GMAC_CLK_RX_DL_CFG(rx_delay) | + RK3568_GMAC_CLK_TX_DL_CFG(tx_delay)); + + regmap_write(data->grf, con1, + RK3568_GMAC_PHY_INTF_SEL_RGMII | + RK3568_GMAC_RXCLK_DLY_ENABLE | + RK3568_GMAC_TXCLK_DLY_ENABLE); + + return 0; +} + +static int rk3568_set_to_rmii(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + u32 con1; + + con1 = (data->id == 1) ? RK3568_GRF_GMAC1_CON1 : + RK3568_GRF_GMAC0_CON1; + regmap_write(data->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII); + + return 0; +} + +static int rk3568_set_gmac_speed(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + ulong rate; + int ret; + + switch (eqos->phy->speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + return -EINVAL; + } + + ret = clk_set_rate(&eqos->clk_tx, rate); + if (ret < 0) + return ret; + + return 0; +} + +/* sys_grf */ +#define RK3588_GRF_GMAC_CON7 0x031c +#define RK3588_GRF_GMAC_CON8 0x0320 +#define RK3588_GRF_GMAC_CON9 0x0324 + +#define RK3588_GMAC_RXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 3) +#define RK3588_GMAC_RXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 3) +#define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2) +#define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2) + +#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) +#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) + +/* php_grf */ +#define RK3588_GRF_GMAC_CON0 0x0008 +#define RK3588_GRF_CLK_CON1 0x0070 + +#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \ + (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6)) +#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \ + (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6)) + +#define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id)) +#define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id)) + +#define RK3588_GMAC_CLK_SELET_CRU(id) GRF_BIT(5 * (id) + 4) +#define RK3588_GMAC_CLK_SELET_IO(id) GRF_CLR_BIT(5 * (id) + 4) + +#define RK3588_GMAC_CLK_RMII_DIV2(id) GRF_BIT(5 * (id) + 2) +#define RK3588_GMAC_CLK_RMII_DIV20(id) GRF_CLR_BIT(5 * (id) + 2) + +#define RK3588_GMAC_CLK_RGMII_DIV1(id) \ + (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_RGMII_DIV5(id) \ + (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) +#define RK3588_GMAC_CLK_RGMII_DIV50(id) \ + (GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) + +#define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1) +#define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1) + +static int rk3588_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, id = data->id; + + offset_con = data->id == 1 ? RK3588_GRF_GMAC_CON9 : + RK3588_GRF_GMAC_CON8; + + regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0, + RK3588_GMAC_PHY_INTF_SEL_RGMII(id)); + + regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, + RK3588_GMAC_CLK_RGMII_MODE(id)); + + regmap_write(data->grf, RK3588_GRF_GMAC_CON7, + RK3588_GMAC_RXCLK_DLY_ENABLE(id) | + RK3588_GMAC_TXCLK_DLY_ENABLE(id)); + + regmap_write(data->grf, offset_con, + RK3588_GMAC_CLK_RX_DL_CFG(rx_delay) | + RK3588_GMAC_CLK_TX_DL_CFG(tx_delay)); + + return 0; +} + +static int rk3588_set_to_rmii(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0, + RK3588_GMAC_PHY_INTF_SEL_RMII(data->id)); + + regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, + RK3588_GMAC_CLK_RMII_MODE(data->id)); + + return 0; +} + +static int rk3588_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, id = data->id; + + switch (eqos->phy->speed) { + case SPEED_10: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = RK3588_GMAC_CLK_RMII_DIV20(id); + else + val = RK3588_GMAC_CLK_RGMII_DIV50(id); + break; + case SPEED_100: + if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII) + val = RK3588_GMAC_CLK_RMII_DIV2(id); + else + val = RK3588_GMAC_CLK_RGMII_DIV5(id); + break; + case SPEED_1000: + if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII) + val = RK3588_GMAC_CLK_RGMII_DIV1(id); + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val); + + return 0; +} + +static void rk3588_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 ? RK3588_GMAC_CLK_SELET_IO(data->id) : + RK3588_GMAC_CLK_SELET_CRU(data->id); + + val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(data->id) : + RK3588_GMAC_CLK_RMII_GATE(data->id); + + regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val); +} + +static const struct rk_gmac_ops rk_gmac_ops[] = { + { + .compatible = "rockchip,rk3568-gmac", + .set_to_rgmii = rk3568_set_to_rgmii, + .set_to_rmii = rk3568_set_to_rmii, + .set_gmac_speed = rk3568_set_gmac_speed, + .regs = { + 0xfe2a0000, /* gmac0 */ + 0xfe010000, /* gmac1 */ + 0x0, /* sentinel */ + }, + }, + { + .compatible = "rockchip,rk3588-gmac", + .set_to_rgmii = rk3588_set_to_rgmii, + .set_to_rmii = rk3588_set_to_rmii, + .set_gmac_speed = rk3588_set_gmac_speed, + .set_clock_selection = rk3588_set_clock_selection, + .regs = { + 0xfe1b0000, /* gmac0 */ + 0xfe1c0000, /* gmac1 */ + 0x0, /* sentinel */ + }, + }, + { } +}; + +static const struct rk_gmac_ops *get_rk_gmac_ops(struct udevice *dev) +{ + const struct rk_gmac_ops *ops = rk_gmac_ops; + + while (ops->compatible) { + if (device_is_compatible(dev, ops->compatible)) + return ops; + ops++; + } + + return NULL; +} + +static int eqos_probe_resources_rk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data; + const char *clock_in_out; + int reset_flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE; + int ret; + + data = calloc(1, sizeof(struct rockchip_platform_data)); + if (!data) + return -ENOMEM; + + data->ops = get_rk_gmac_ops(dev); + if (!data->ops) { + ret = -EINVAL; + goto err_free; + } + + for (int i = 0; data->ops->regs[i]; i++) { + if (data->ops->regs[i] == (u32)eqos->regs) { + data->id = i; + break; + } + } + + pdata->priv_pdata = data; + pdata->phy_interface = eqos->config->interface(dev); + pdata->max_speed = eqos->max_speed; + + if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + pr_err("Invalid PHY interface\n"); + ret = -EINVAL; + goto err_free; + } + + data->grf = syscon_regmap_lookup_by_phandle(dev, "rockchip,grf"); + if (IS_ERR(data->grf)) { + dev_err(dev, "Missing rockchip,grf property\n"); + ret = -EINVAL; + goto err_free; + } + + if (device_is_compatible(dev, "rockchip,rk3588-gmac")) { + data->php_grf = + syscon_regmap_lookup_by_phandle(dev, "rockchip,php-grf"); + if (IS_ERR(data->php_grf)) { + dev_err(dev, "Missing rockchip,php-grf property\n"); + ret = -EINVAL; + goto err_free; + } + } + + ret = reset_get_bulk(dev, &data->resets); + if (ret < 0) + goto err_free; + + reset_assert_bulk(&data->resets); + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + dev_dbg(dev, "clk_get_by_name(stmmaceth) failed: %d", ret); + goto err_release_resets; + } + + if (device_is_compatible(dev, "rockchip,rk3568-gmac")) { + ret = clk_get_by_name(dev, "clk_mac_speed", &eqos->clk_tx); + if (ret) { + dev_dbg(dev, "clk_get_by_name(clk_mac_speed) failed: %d", ret); + goto err_free_clk_master_bus; + } + } + + clock_in_out = dev_read_string(dev, "clock_in_out"); + if (clock_in_out && !strcmp(clock_in_out, "input")) + data->clock_input = true; + else + data->clock_input = false; + + /* snps,reset props are deprecated, do bare minimum to support them */ + if (dev_read_bool(dev, "snps,reset-active-low")) + reset_flags |= GPIOD_ACTIVE_LOW; + + dev_read_u32_array(dev, "snps,reset-delays-us", eqos->reset_delays, 3); + + gpio_request_by_name(dev, "snps,reset-gpio", 0, + &eqos->phy_reset_gpio, reset_flags); + + return 0; + +err_free_clk_master_bus: + clk_free(&eqos->clk_master_bus); +err_release_resets: + reset_release_bulk(&data->resets); +err_free: + free(data); + + return ret; +} + +static int eqos_remove_resources_rk(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; + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) + dm_gpio_free(dev, &eqos->phy_reset_gpio); + + clk_free(&eqos->clk_tx); + clk_free(&eqos->clk_master_bus); + reset_release_bulk(&data->resets); + free(data); + + return 0; +} + +static int eqos_stop_resets_rk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + return reset_assert_bulk(&data->resets); +} + +static int eqos_start_resets_rk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + return reset_deassert_bulk(&data->resets); +} + +static int eqos_stop_clks_rk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + if (data->ops->set_clock_selection) + data->ops->set_clock_selection(dev, false); + + return 0; +} + +static int eqos_start_clks_rk(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; + int tx_delay, rx_delay, ret; + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { + udelay(eqos->reset_delays[1]); + + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); + if (ret < 0) + return ret; + + udelay(eqos->reset_delays[2]); + } + + if (data->ops->set_clock_selection) + data->ops->set_clock_selection(dev, true); + + tx_delay = dev_read_u32_default(dev, "tx_delay", 0x30); + rx_delay = dev_read_u32_default(dev, "rx_delay", 0x10); + + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + return data->ops->set_to_rgmii(dev, tx_delay, rx_delay); + case PHY_INTERFACE_MODE_RGMII_ID: + return data->ops->set_to_rgmii(dev, 0, 0); + case PHY_INTERFACE_MODE_RGMII_RXID: + return data->ops->set_to_rgmii(dev, tx_delay, 0); + case PHY_INTERFACE_MODE_RGMII_TXID: + return data->ops->set_to_rgmii(dev, 0, rx_delay); + case PHY_INTERFACE_MODE_RMII: + return data->ops->set_to_rmii(dev); + } + + return -EINVAL; +} + +static int eqos_set_tx_clk_speed_rk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct rockchip_platform_data *data = pdata->priv_pdata; + + return data->ops->set_gmac_speed(dev); +} + +static ulong eqos_get_tick_clk_rate_rk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + return clk_get_rate(&eqos->clk_master_bus); +} + +static struct eqos_ops eqos_rockchip_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_rk, + .eqos_remove_resources = eqos_remove_resources_rk, + .eqos_stop_resets = eqos_stop_resets_rk, + .eqos_start_resets = eqos_start_resets_rk, + .eqos_stop_clks = eqos_stop_clks_rk, + .eqos_start_clks = eqos_start_clks_rk, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_rk, + .eqos_get_enetaddr = eqos_null_ops, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_rk, +}; + +struct eqos_config eqos_rockchip_config = { + .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_100_150, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_rockchip_ops, +}; diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 984616fb65c..f5c5057bec1 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -30,6 +30,8 @@ #include <fsl-mc/fsl_qbman_portal.h> #include <fsl-mc/ldpaa_wriop.h> #include <net/ldpaa_eth.h> +#include <asm/arch/cpu.h> +#include <asm/arch-fsl-layerscape/fsl_icid.h> #define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024) #define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1)) @@ -929,6 +931,114 @@ unsigned long mc_get_dram_block_size(void) return dram_block_size; } +/** + * Populate the device tree with MC reserved memory ranges. + */ +void fdt_reserve_mc_mem(void *blob, u32 mc_icid) +{ + u32 phandle, mc_ph; + int noff, ret, i; + char mem_name[16]; + struct fdt_memory mc_mem_ranges[] = { + { + .start = 0, + .end = 0 + }, + { + .start = CFG_SYS_FSL_MC_BASE, + .end = CFG_SYS_FSL_MC_BASE + CFG_SYS_FSL_MC_SIZE - 1 + }, + { + .start = CFG_SYS_FSL_NI_BASE, + .end = CFG_SYS_FSL_NI_BASE + CFG_SYS_FSL_NI_SIZE - 1 + }, + { + .start = CFG_SYS_FSL_QBMAN_BASE, + .end = CFG_SYS_FSL_QBMAN_BASE + + CFG_SYS_FSL_QBMAN_SIZE - 1 + }, + { + .start = CFG_SYS_FSL_PEBUF_BASE, + .end = CFG_SYS_FSL_PEBUF_BASE + + CFG_SYS_FSL_PEBUF_SIZE - 1 + }, + { + .start = CFG_SYS_FSL_CCSR_BASE, + .end = CFG_SYS_FSL_CCSR_BASE + CFG_SYS_FSL_CCSR_SIZE - 1 + } + }; + + mc_mem_ranges[0].start = gd->arch.resv_ram; + mc_mem_ranges[0].end = mc_mem_ranges[0].start + + mc_get_dram_block_size() - 1; + + for (i = 0; i < ARRAY_SIZE(mc_mem_ranges); i++) { + noff = fdt_node_offset_by_compatible(blob, -1, "fsl,qoriq-mc"); + if (noff < 0) { + printf("WARN: failed to get MC node: %d\n", noff); + return; + } + mc_ph = fdt_get_phandle(blob, noff); + if (!mc_ph) { + mc_ph = fdt_create_phandle(blob, noff); + if (!mc_ph) { + printf("WARN: failed to get MC node phandle\n"); + return; + } + } + + sprintf(mem_name, "mc-mem%d", i); + ret = fdtdec_add_reserved_memory(blob, mem_name, + &mc_mem_ranges[i], NULL, 0, + &phandle, 0); + if (ret < 0) { + printf("ERROR: failed to reserve MC memory: %d\n", ret); + return; + } + + noff = fdt_node_offset_by_phandle(blob, phandle); + if (noff < 0) { + printf("ERROR: failed get resvmem node offset: %d\n", + noff); + return; + } + ret = fdt_setprop_u32(blob, noff, "iommu-addresses", mc_ph); + if (ret < 0) { + printf("ERROR: failed to set 'iommu-addresses': %d\n", + ret); + return; + } + ret = fdt_appendprop_u64(blob, noff, "iommu-addresses", + mc_mem_ranges[i].start); + if (ret < 0) { + printf("ERROR: failed to set 'iommu-addresses': %d\n", + ret); + return; + } + ret = fdt_appendprop_u64(blob, noff, "iommu-addresses", + mc_mem_ranges[i].end - + mc_mem_ranges[i].start + 1); + if (ret < 0) { + printf("ERROR: failed to set 'iommu-addresses': %d\n", + ret); + return; + } + + noff = fdt_node_offset_by_phandle(blob, mc_ph); + if (noff < 0) { + printf("ERROR: failed get MC node offset: %d\n", noff); + return; + } + ret = fdt_appendprop_u32(blob, noff, "memory-region", phandle); + if (ret < 0) { + printf("ERROR: failed to set 'memory-region': %d\n", + ret); + } + } + + fdt_set_iommu_prop(blob, noff, fdt_get_smmu_phandle(blob), &mc_icid, 1); +} + int fsl_mc_ldpaa_init(struct bd_info *bis) { int i; diff --git a/drivers/net/phy/xilinx_phy.c b/drivers/net/phy/xilinx_phy.c index 1df639d6f44..c07c780193f 100644 --- a/drivers/net/phy/xilinx_phy.c +++ b/drivers/net/phy/xilinx_phy.c @@ -99,7 +99,6 @@ static int xilinxphy_startup(struct phy_device *phydev) static int xilinxphy_of_init(struct phy_device *phydev) { - u32 phytype; ofnode node; debug("%s\n", __func__); @@ -107,10 +106,6 @@ static int xilinxphy_of_init(struct phy_device *phydev) if (!ofnode_valid(node)) return -EINVAL; - phytype = ofnode_read_u32_default(node, "xlnx,phy-type", -1); - if (phytype == XAE_PHY_TYPE_1000BASE_X) - phydev->flags |= XAE_PHY_TYPE_1000BASE_X; - return 0; } diff --git a/drivers/net/sni_netsec.c b/drivers/net/sni_netsec.c index 9780f2092bd..71afe78fd28 100644 --- a/drivers/net/sni_netsec.c +++ b/drivers/net/sni_netsec.c @@ -286,6 +286,8 @@ struct netsec_rx_pkt_info { bool err_flag; }; +static int netsec_reset_hardware(struct netsec_priv *priv, bool load_ucode); + static void netsec_write_reg(struct netsec_priv *priv, u32 reg_addr, u32 val) { writel(val, priv->ioaddr + reg_addr); @@ -532,18 +534,11 @@ static int netsec_mac_update_to_phy_state(struct netsec_priv *priv) return 0; } -static int netsec_start_gmac(struct netsec_priv *priv) +static int netsec_reset_gmac(struct netsec_priv *priv) { u32 value = 0; int ret; - if (priv->max_speed != SPEED_1000) - value = (NETSEC_GMAC_MCR_REG_CST | - NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON); - - if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) - return -ETIMEDOUT; - if (netsec_set_mac_reg(priv, GMAC_REG_BMR, NETSEC_GMAC_BMR_REG_RESET)) return -ETIMEDOUT; @@ -558,10 +553,47 @@ static int netsec_start_gmac(struct netsec_priv *priv) if (value & NETSEC_GMAC_BMR_REG_SWR) return -EAGAIN; + /** + * NETSEC GMAC sometimes shows the peculiar behaviour where + * MAC_REG_DESC_SOFT_RST never been cleared, resulting in the loss of + * sending packets. + * + * Workaround: + * Restart NETSEC and PHY, retry again. + */ netsec_write_reg(priv, MAC_REG_DESC_SOFT_RST, 1); - if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1)) + udelay(1000); + if (netsec_read_reg(priv, MAC_REG_DESC_SOFT_RST)) { + phy_shutdown(priv->phydev); + netsec_reset_hardware(priv, false); + phy_startup(priv->phydev); + return -EAGAIN; + } + return 0; +} + +static int netsec_start_gmac(struct netsec_priv *priv) +{ + u32 value = 0; + u32 failure = 0; + int ret; + + if (priv->max_speed != SPEED_1000) + value = (NETSEC_GMAC_MCR_REG_CST | + NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON); + + if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) return -ETIMEDOUT; + /* Reset GMAC */ + while ((ret = netsec_reset_gmac(priv)) == -EAGAIN && ++failure < 3) + ; + + if (ret) { + pr_err("%s: failed to reset gmac(err=%d).\n", __func__, ret); + return ret; + } + netsec_write_reg(priv, MAC_REG_DESC_INIT, 1); if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1)) return -ETIMEDOUT; diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 04c3274fbe1..4ba9ee1529e 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -29,6 +29,7 @@ #include <net.h> #include <reset.h> #include <wait_bit.h> +#include <power/regulator.h> #define MDIO_CMD_MII_BUSY BIT(0) #define MDIO_CMD_MII_WRITE BIT(1) @@ -170,6 +171,7 @@ struct emac_eth_dev { #if CONFIG_IS_ENABLED(DM_GPIO) struct gpio_desc reset_gpio; #endif + struct udevice *phy_reg; }; @@ -720,6 +722,9 @@ static int sun8i_emac_eth_probe(struct udevice *dev) sun8i_emac_set_syscon(sun8i_pdata, priv); + if (priv->phy_reg) + regulator_set_enable(priv->phy_reg, true); + sun8i_mdio_init(dev->name, dev); priv->bus = miiphy_get_dev_by_name(dev->name); @@ -829,6 +834,8 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev) priv->sysctl_reg = (void *)syscon_base + priv->variant->syscon_offset; + device_get_supply_regulator(dev, "phy-supply", &priv->phy_reg); + pdata->phy_interface = -1; priv->phyaddr = -1; priv->use_internal_phy = false; diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 4c90d4b4981..f546ad1fe8d 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -17,6 +17,7 @@ #include <net.h> #include <asm/io.h> #include <asm/arch/clock.h> +#include <power/regulator.h> /* EMAC register */ struct emac_regs { @@ -165,6 +166,7 @@ struct emac_eth_dev { struct phy_device *phydev; int link_printed; uchar rx_buf[EMAC_RX_BUFSIZE]; + struct udevice *phy_reg; }; struct emac_rxhdr { @@ -572,6 +574,9 @@ static int sunxi_emac_eth_probe(struct udevice *dev) if (ret) return ret; + if (priv->phy_reg) + regulator_set_enable(priv->phy_reg, true); + return sunxi_emac_init_phy(priv, dev); } @@ -585,9 +590,42 @@ static const struct eth_ops sunxi_emac_eth_ops = { static int sunxi_emac_eth_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); + struct emac_eth_dev *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + ofnode phy_node, mdio_node; + int ret; pdata->iobase = dev_read_addr(dev); + phy_node = dev_get_phy_node(dev); + if (!ofnode_valid(phy_node)) { + dev_err(dev, "failed to get PHY node\n"); + return -ENOENT; + } + /* + * The PHY regulator is in the MDIO node, not the EMAC or PHY node. + * U-Boot does not have (and does not need) a device driver for the + * MDIO device, so just "pass through" that DT node to get to the + * regulator phandle. + * The PHY regulator is optional, though: ignore if we cannot find + * a phy-supply property. + */ + mdio_node = ofnode_get_parent(phy_node); + ret= ofnode_parse_phandle_with_args(mdio_node, "phy-supply", NULL, 0, 0, + &args); + if (ret && ret != -ENOENT) { + dev_err(dev, "failed to get PHY supply node\n"); + return ret; + } + if (!ret) { + ret = uclass_get_device_by_ofnode(UCLASS_REGULATOR, args.node, + &priv->phy_reg); + if (ret) { + dev_err(dev, "failed to get PHY regulator node\n"); + return ret; + } + } + return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 3377e669f2f..7c57d32614f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -321,11 +321,38 @@ static int zynq_gem_setup_mac(struct udevice *dev) return 0; } +static u32 gem_mdc_clk_div(struct zynq_gem_priv *priv) +{ + u32 config; + unsigned long pclk_hz; + + pclk_hz = clk_get_rate(&priv->pclk); + if (pclk_hz <= 20000000) + config = GEM_MDC_SET(GEM_CLK_DIV8); + else if (pclk_hz <= 40000000) + config = GEM_MDC_SET(GEM_CLK_DIV16); + else if (pclk_hz <= 80000000) + config = GEM_MDC_SET(GEM_CLK_DIV32); + else if (pclk_hz <= 120000000) + config = GEM_MDC_SET(GEM_CLK_DIV48); + else if (pclk_hz <= 160000000) + config = GEM_MDC_SET(GEM_CLK_DIV64); + else if (pclk_hz <= 240000000) + config = GEM_MDC_SET(GEM_CLK_DIV96); + else if (pclk_hz <= 320000000) + config = GEM_MDC_SET(GEM_CLK_DIV128); + else + config = GEM_MDC_SET(GEM_CLK_DIV224); + + return config; +} + static int zynq_phy_init(struct udevice *dev) { - int ret; + int ret, val; struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs_mdio = priv->mdiobase; + struct zynq_gem_regs *regs = priv->iobase; const u32 supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | @@ -333,6 +360,10 @@ static int zynq_phy_init(struct udevice *dev) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + val = gem_mdc_clk_div(priv); + if (val) + writel(val, ®s->nwcfg); + /* Enable only MDIO bus */ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s_mdio->nwctrl); @@ -360,35 +391,10 @@ static int zynq_phy_init(struct udevice *dev) return phy_config(priv->phydev); } -static u32 gem_mdc_clk_div(struct zynq_gem_priv *priv) -{ - u32 config; - unsigned long pclk_hz; - - pclk_hz = clk_get_rate(&priv->pclk); - if (pclk_hz <= 20000000) - config = GEM_MDC_SET(GEM_CLK_DIV8); - else if (pclk_hz <= 40000000) - config = GEM_MDC_SET(GEM_CLK_DIV16); - else if (pclk_hz <= 80000000) - config = GEM_MDC_SET(GEM_CLK_DIV32); - else if (pclk_hz <= 120000000) - config = GEM_MDC_SET(GEM_CLK_DIV48); - else if (pclk_hz <= 160000000) - config = GEM_MDC_SET(GEM_CLK_DIV64); - else if (pclk_hz <= 240000000) - config = GEM_MDC_SET(GEM_CLK_DIV96); - else if (pclk_hz <= 320000000) - config = GEM_MDC_SET(GEM_CLK_DIV128); - else - config = GEM_MDC_SET(GEM_CLK_DIV224); - - return config; -} static int zynq_gem_init(struct udevice *dev) { - u32 i, nwconfig; + u32 i, nwconfig, nwcfg; int ret; unsigned long clk_rate = 0; struct zynq_gem_priv *priv = dev_get_priv(dev); @@ -494,8 +500,7 @@ static int zynq_gem_init(struct udevice *dev) return -1; } - nwconfig = gem_mdc_clk_div(priv); - nwconfig |= ZYNQ_GEM_NWCFG_INIT; + nwconfig = ZYNQ_GEM_NWCFG_INIT; /* * Set SGMII enable PCS selection only if internal PCS/PMA @@ -509,19 +514,21 @@ static int zynq_gem_init(struct udevice *dev) switch (priv->phydev->speed) { case SPEED_1000: - writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED1000, - ®s->nwcfg); + nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000; clk_rate = ZYNQ_GEM_FREQUENCY_1000; break; case SPEED_100: - writel(nwconfig | ZYNQ_GEM_NWCFG_SPEED100, - ®s->nwcfg); + nwconfig |= ZYNQ_GEM_NWCFG_SPEED100; clk_rate = ZYNQ_GEM_FREQUENCY_100; break; case SPEED_10: clk_rate = ZYNQ_GEM_FREQUENCY_10; break; } + nwcfg = readl(®s->nwcfg); + nwcfg |= nwconfig; + if (nwcfg) + writel(nwcfg, ®s->nwcfg); #ifdef CONFIG_ARM64 if (priv->interface == PHY_INTERFACE_MODE_SGMII && |