Przeglądaj źródła

net: dwc_eth_qos:starfive: add jh7110 support

Add new configuration for jh7110 soc platform.

Signed-off-by: yanhong.wang <yanhong.wang@starfivetech.com>
yanhong.wang 2 lat temu
rodzic
commit
461cd1afbe
2 zmienionych plików z 290 dodań i 0 usunięć
  1. 7 0
      drivers/net/Kconfig
  2. 283 0
      drivers/net/dwc_eth_qos.c

+ 7 - 0
drivers/net/Kconfig

@@ -220,6 +220,13 @@ config DWC_ETH_QOS_TEGRA186
 	  The Synopsys Designware Ethernet QOS IP block with specific
 	  configuration used in NVIDIA's Tegra186 chip.
 
+config DWC_ETH_QOS_STARFIVE
+	bool "Synopsys DWC Ethernet QOS device support for STARFIVE"
+	depends on DWC_ETH_QOS
+	help
+	  The Synopsys Designware Ethernet QOS IP block with the specific
+	  configuration used in STARFIVE soc.
+
 config E1000
 	bool "Intel PRO/1000 Gigabit Ethernet support"
 	help

+ 283 - 0
drivers/net/dwc_eth_qos.c

@@ -131,7 +131,11 @@ struct eqos_mac_regs {
 #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT			16
 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT			8
 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35			2
+#if CONFIG_IS_ENABLED(STARFIVE_JH7110)
+#define EQOS_MAC_MDIO_ADDRESS_CR_250_300		9
+#else
 #define EQOS_MAC_MDIO_ADDRESS_CR_250_300		5
+#endif
 #define EQOS_MAC_MDIO_ADDRESS_SKAP			BIT(4)
 #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT			2
 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ			3
@@ -319,6 +323,7 @@ struct eqos_priv {
 	bool started;
 	bool reg_access_ok;
 	bool clk_ck_enabled;
+	struct reset_ctl_bulk reset_bulk;
 };
 
 /*
@@ -615,6 +620,57 @@ err:
 #endif
 }
 
+static int eqos_start_clks_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	int ret;
+
+	ret = clk_enable(&eqos->clk_slave_bus);
+	if (ret < 0) {
+		pr_err("clk_enable(clk_slave_bus) failed: %d", ret);
+		goto err;
+	}
+
+	ret = clk_enable(&eqos->clk_master_bus);
+	if (ret < 0) {
+		pr_err("clk_enable(clk_master_bus) failed: %d", ret);
+		goto err_disable_clk_slave_bus;
+	}
+
+	ret = clk_enable(&eqos->clk_ck);
+	if (ret < 0) {
+		pr_err("clk_enable(clk_ck) failed: %d", ret);
+		goto err_disable_clk_master_bus;
+	}
+
+	ret = clk_enable(&eqos->clk_ptp_ref);
+	if (ret < 0) {
+		pr_err("clk_enable(clk_ptp_ref) failed: %d", ret);
+		goto err_disable_clk_gtx;
+	}
+
+	ret = clk_enable(&eqos->clk_tx);
+	if (ret < 0) {
+		pr_err("clk_enable(clk_tx) failed: %d", ret);
+		goto err_disable_clk_ptp_ref;
+	}
+
+	debug("%s: OK\n", __func__);
+	return 0;
+
+err_disable_clk_ptp_ref:
+	clk_disable(&eqos->clk_ptp_ref);
+err_disable_clk_gtx:
+	clk_disable(&eqos->clk_rx);
+err_disable_clk_master_bus:
+	clk_disable(&eqos->clk_master_bus);
+err_disable_clk_slave_bus:
+	clk_disable(&eqos->clk_slave_bus);
+err:
+	debug("%s: FAILED: %d\n", __func__, ret);
+	return ret;
+}
+
 static int eqos_stop_clks_tegra186(struct udevice *dev)
 {
 #ifdef CONFIG_CLK
@@ -649,6 +705,20 @@ static int eqos_stop_clks_stm32(struct udevice *dev)
 	return 0;
 }
 
+static int eqos_stop_clks_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+
+	clk_disable(&eqos->clk_tx);
+	clk_disable(&eqos->clk_ptp_ref);
+	clk_disable(&eqos->clk_ck);
+	clk_disable(&eqos->clk_master_bus);
+	clk_disable(&eqos->clk_slave_bus);
+
+	debug("%s: OK\n", __func__);
+	return 0;
+}
+
 static int eqos_start_resets_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -688,6 +758,27 @@ static int eqos_start_resets_tegra186(struct udevice *dev)
 	return 0;
 }
 
+static int eqos_start_resets_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	int ret;
+
+	ret = reset_deassert_bulk(&eqos->reset_bulk);
+	if (ret < 0) {
+		pr_err("reset_deassert() failed: %d", ret);
+		return ret;
+	}
+
+	ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+	if (ret < 0) {
+		pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret);
+		return ret;
+	}
+
+	debug("%s: OK\n", __func__);
+	return 0;
+}
+
 static int eqos_stop_resets_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -698,6 +789,17 @@ static int eqos_stop_resets_tegra186(struct udevice *dev)
 	return 0;
 }
 
+static int eqos_stop_resets_jh7110(struct udevice *dev)
+{
+//	struct eqos_priv *eqos = dev_get_priv(dev);
+
+//	reset_assert_bulk(&eqos->reset_bulk);
+//	dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
+
+	return 0;
+}
+
+
 static int eqos_calibrate_pads_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -772,6 +874,16 @@ static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
 #endif
 }
 
+static ulong eqos_get_tick_clk_rate_jh7110(struct udevice *dev)
+{
+	return 4000000;
+}
+
+__weak int jh7110_eqos_txclk_set_rate(unsigned long rate)
+{
+	return 0;
+}
+
 __weak u32 imx_get_eqos_csr_clk(void)
 {
 	return 100 * 1000000;
@@ -914,6 +1026,36 @@ static int eqos_set_tx_clk_speed_imx(struct udevice *dev)
 	return 0;
 }
 
+static int eqos_set_tx_clk_speed_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	ulong rate;
+	int ret;
+
+	switch (eqos->phy->speed) {
+	case SPEED_1000:
+		rate = 125 * 1000 * 1000;
+		break;
+	case SPEED_100:
+		rate = 25 * 1000 * 1000;
+		break;
+	case SPEED_10:
+		rate = 2.5 * 1000 * 1000;
+		break;
+	default:
+		pr_err("invalid speed %d", eqos->phy->speed);
+		return -EINVAL;
+	}
+
+	ret = jh7110_eqos_txclk_set_rate(rate);
+	if (ret < 0) {
+		pr_err("jh7110 (tx_clk, %lu) failed: %d", rate, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int eqos_adjust_link(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1789,6 +1931,97 @@ static phy_interface_t eqos_get_interface_imx(struct udevice *dev)
 	return interface;
 }
 
+static int eqos_probe_resources_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+	phy_interface_t interface;
+	int ret;
+
+	interface = eqos->config->interface(dev);
+
+	if (interface == PHY_INTERFACE_MODE_NONE) {
+		pr_err("Invalid PHY interface\n");
+		return -EINVAL;
+	}
+
+	ret = reset_get_bulk(dev, &eqos->reset_bulk);
+	if (ret) {
+		pr_err("Can't get reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "phy-reset-gpios", 0,
+				   &eqos->phy_reset_gpio,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret) {
+		pr_err("gpio_request_by_name(phy reset) failed: %d", ret);
+		goto err_free_reset_eqos;
+	}
+
+	ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
+	if (ret) {
+		pr_err("clk_get_by_name(master_bus) failed: %d", ret);
+		goto err_free_gpio_phy_reset;
+	}
+
+	ret = clk_get_by_name(dev, "pclk", &eqos->clk_slave_bus);
+	if (ret) {
+		pr_err("clk_get_by_name(slave_bus) failed: %d", ret);
+		goto err_free_clk_master_bus;
+	}
+
+	ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref);
+	if (ret) {
+		pr_err("clk_get_by_name(ptp_ref) failed: %d", ret);
+		goto err_free_clk_slave_bus;
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "gtx", &eqos->clk_ck);
+	if (ret) {
+		pr_err("clk_get_by_name(gtx) failed: %d", ret);
+		goto err_free_clk_ptp_ref;
+	}
+
+	ret = clk_get_by_name(dev, "tx", &eqos->clk_tx);
+	if (ret) {
+		pr_err("clk_get_by_name(tx) failed: %d", ret);
+		goto err_free_clk_gtx;
+	}
+
+	debug("%s: OK\n", __func__);
+	return 0;
+
+err_free_clk_gtx:
+	clk_free(&eqos->clk_ck);
+err_free_clk_ptp_ref:
+	clk_free(&eqos->clk_ptp_ref);
+err_free_clk_slave_bus:
+	clk_free(&eqos->clk_slave_bus);
+err_free_clk_master_bus:
+	clk_free(&eqos->clk_master_bus);
+err_free_gpio_phy_reset:
+	dm_gpio_free(dev, &eqos->phy_reset_gpio);
+err_free_reset_eqos:
+	reset_release_bulk(&eqos->reset_bulk);
+
+	return ret;
+}
+
+static phy_interface_t eqos_get_interface_jh7110(struct udevice *dev)
+{
+	const char *phy_mode;
+	phy_interface_t interface = PHY_INTERFACE_MODE_NONE;
+
+	debug("%s(dev=%p):\n", __func__, dev);
+
+	phy_mode = dev_read_prop(dev, "phy-mode", NULL);
+	if (phy_mode)
+		interface = phy_get_interface_by_name(phy_mode);
+
+	return interface;
+}
+
 static int eqos_remove_resources_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1830,6 +2063,22 @@ static int eqos_remove_resources_stm32(struct udevice *dev)
 	return 0;
 }
 
+static int eqos_remove_resources_jh7110(struct udevice *dev)
+{
+	struct eqos_priv *eqos = dev_get_priv(dev);
+
+	clk_free(&eqos->clk_tx);
+	clk_free(&eqos->clk_ptp_ref);
+	clk_free(&eqos->clk_ck);
+	clk_free(&eqos->clk_slave_bus);
+	clk_free(&eqos->clk_master_bus);
+	dm_gpio_free(dev, &eqos->phy_reset_gpio);
+	reset_release_bulk(&eqos->reset_bulk);
+
+	debug("%s: OK\n", __func__);
+	return 0;
+}
+
 static int eqos_probe(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
@@ -2017,6 +2266,34 @@ struct eqos_config __maybe_unused eqos_imx_config = {
 	.ops = &eqos_imx_ops
 };
 
+static struct eqos_ops eqos_jh7110_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_jh7110,
+	.eqos_remove_resources = eqos_remove_resources_jh7110,
+	.eqos_stop_resets = eqos_stop_resets_jh7110,
+	.eqos_start_resets = eqos_start_resets_jh7110,
+	.eqos_stop_clks = eqos_stop_clks_jh7110,
+	.eqos_start_clks = eqos_start_clks_jh7110,
+	.eqos_calibrate_pads = eqos_null_ops,
+	.eqos_disable_calibration = eqos_null_ops,
+	.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_jh7110,
+	.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_jh7110
+};
+
+struct eqos_config __maybe_unused eqos_jh7110_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_250_300,
+	.axi_bus_width = EQOS_AXI_WIDTH_64,
+	.interface = eqos_get_interface_jh7110,
+	.ops = &eqos_jh7110_ops
+};
+
 static const struct udevice_id eqos_ids[] = {
 #if IS_ENABLED(CONFIG_DWC_ETH_QOS_TEGRA186)
 	{
@@ -2036,6 +2313,12 @@ static const struct udevice_id eqos_ids[] = {
 		.data = (ulong)&eqos_imx_config
 	},
 #endif
+#if IS_ENABLED(CONFIG_DWC_ETH_QOS_STARFIVE)
+	{
+		.compatible = "starfive,jh7110-eqos-5.20",
+		.data = (ulong)&eqos_jh7110_config
+	},
+#endif
 
 	{ }
 };