the stmmac device driver. This driver is used for the Intel Keem Bay
SoC.
+config DWMAC_STARFIVE_PLAT
+ tristate "StarFive dwmac support"
+ depends on OF && COMMON_CLK
+ depends on STMMAC_ETH
+ help
+ Support for ethernet controllers on StarFive SoCs
+
+ This selects the StarFive platform specific glue layer support for
+ the stmmac device driver. This driver is used for StarFive SoCs.
+
config DWMAC_VISCONTI
tristate "Toshiba Visconti DWMAC support"
default ARCH_VISCONTI
obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o
+obj-$(CONFIG_DWMAC_STARFIVE_PLAT) += dwmac-starfive-plat.o
obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o
obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o
struct gpio_desc *reset;
};
-struct starfive_eqos {
- struct device *dev;
- void __iomem *regs;
- struct clk *clk_tx;
- struct clk *clk_gtx;
- struct clk *clk_gtxc;
-};
-
static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
struct plat_stmmacenet_data *plat_dat)
{
return 0;
}
-static void starfive_eqos_fix_speed(void *priv, unsigned int speed)
-{
- struct starfive_eqos *eqos = priv;
- unsigned long rate;
- int err;
-
- switch (speed) {
- case SPEED_1000:
- rate = 125000000;
- break;
- case SPEED_100:
- rate = 25000000;
- break;
- case SPEED_10:
- rate = 2500000;
- break;
- default:
- dev_err(eqos->dev, "invalid speed %u\n", speed);
- return;
- }
-
- err = clk_set_rate(eqos->clk_gtx, rate);
- if (err < 0)
- dev_err(eqos->dev, "failed to set tx rate %lu\n", rate);
-}
-
-static int starfive_eqos_probe(struct platform_device *pdev,
- struct plat_stmmacenet_data *data,
- struct stmmac_resources *res)
-{
- struct device *dev = &pdev->dev;
- struct starfive_eqos *eqos;
- int err;
-
- /* Get IRQ information early to have an ability to ask for deferred
- * probe if needed before we went too far with resource allocation.
- */
- res->irq = platform_get_irq_byname(pdev, "macirq");
- if (res->irq < 0)
- return res->irq;
-
- /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
- * The external wake up irq can be passed through the platform code
- * named as "eth_wake_irq"
- *
- * In case the wake up interrupt is not passed from the platform
- * so the driver will continue to use the mac irq (ndev->irq)
- */
- res->wol_irq =
- platform_get_irq_byname_optional(pdev, "eth_wake_irq");
- if (res->wol_irq < 0) {
- if (res->wol_irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_info(&pdev->dev, "IRQ eth_wake_irq not found\n");
- res->wol_irq = res->irq;
- }
-
- res->lpi_irq =
- platform_get_irq_byname_optional(pdev, "eth_lpi");
- if (res->lpi_irq < 0) {
- if (res->lpi_irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_info(&pdev->dev, "IRQ eth_lpi not found\n");
- }
-
- eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
- if (!eqos)
- return -ENOMEM;
-
- eqos->dev = &pdev->dev;
- eqos->regs = res->addr;
-
- if (!is_of_node(dev->fwnode))
- goto bypass_clk_reset_gpio;
-
- eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
- if (IS_ERR(eqos->clk_tx)) {
- err = PTR_ERR(eqos->clk_tx);
- goto err;
- }
-
- err = clk_prepare_enable(eqos->clk_tx);
- if (err < 0)
- goto err;
-
- eqos->clk_gtx = devm_clk_get(&pdev->dev, "gtx");
- if (IS_ERR(eqos->clk_gtx)) {
- err = PTR_ERR(eqos->clk_gtx);
- goto disable_tx;
- }
-
- err = clk_prepare_enable(eqos->clk_gtx);
- if (err < 0)
- goto disable_tx;
-
- eqos->clk_gtxc = devm_clk_get(&pdev->dev, "gtxc");
- if (IS_ERR(eqos->clk_gtxc)) {
- err = PTR_ERR(eqos->clk_gtxc);
- goto disable_gtx;
- }
-
- err = clk_prepare_enable(eqos->clk_gtxc);
- if (err < 0)
- goto disable_gtx;
-
-bypass_clk_reset_gpio:
- data->fix_mac_speed = starfive_eqos_fix_speed;
- data->init = NULL;
- data->bsp_priv = eqos;
- return 0;
-
-disable_gtx:
- clk_disable_unprepare(eqos->clk_gtx);
-disable_tx:
- clk_disable_unprepare(eqos->clk_tx);
-err:
- return err;
-}
-
-static int starfive_eqos_remove(struct platform_device *pdev)
-{
- struct starfive_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
-
- clk_disable_unprepare(eqos->clk_tx);
- clk_disable_unprepare(eqos->clk_gtx);
-
- return 0;
-}
-
struct dwc_eth_dwmac_data {
int (*probe)(struct platform_device *pdev,
struct plat_stmmacenet_data *data,
.remove = tegra_eqos_remove,
};
-static const struct dwc_eth_dwmac_data starfive_eqos_data = {
- .probe = starfive_eqos_probe,
- .remove = starfive_eqos_remove,
-};
-
static int dwc_eth_dwmac_probe(struct platform_device *pdev)
{
const struct dwc_eth_dwmac_data *data;
static const struct of_device_id dwc_eth_dwmac_match[] = {
{ .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
{ .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
- { .compatible = "starfive,jh7110-eqos-5.20", .data = &starfive_eqos_data },
{ }
};
MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/* StarFive DWMAC platform driver
+ *
+ * Copyright(C) 2022 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/of_device.h>
+#include "stmmac_platform.h"
+
+struct starfive_dwmac {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk_tx;
+ struct clk *clk_gtx;
+ struct clk *clk_gtxc;
+};
+
+static void starfive_eth_fix_mac_speed(void *priv, unsigned int speed)
+{
+ struct starfive_dwmac *dwmac = priv;
+ unsigned long rate;
+ int err;
+
+ switch (speed) {
+ case SPEED_1000:
+ rate = 125000000;
+ break;
+ case SPEED_100:
+ rate = 25000000;
+ break;
+ case SPEED_10:
+ rate = 2500000;
+ break;
+ default:
+ dev_err(dwmac->dev, "invalid speed %u\n", speed);
+ return;
+ }
+
+ err = clk_set_rate(dwmac->clk_gtx, rate);
+ if (err < 0)
+ dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate);
+}
+
+static const struct of_device_id starfive_eth_plat_match[] = {
+ {.compatible = "starfive,dwmac"},
+ { }
+};
+
+static int starfive_eth_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct plat_stmmacenet_data *plat_dat;
+ struct stmmac_resources stmmac_res;
+ struct starfive_dwmac *dwmac;
+ int err;
+
+ err = stmmac_get_platform_resources(pdev, &stmmac_res);
+ if (err)
+ return err;
+
+ plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
+ if (IS_ERR(plat_dat)) {
+ dev_err(&pdev->dev, "dt configuration failed\n");
+ return PTR_ERR(plat_dat);
+ }
+
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+ if (!dwmac)
+ return -ENOMEM;
+
+ dwmac->dev = &pdev->dev;
+ dwmac->regs = stmmac_res.addr;
+
+ if (!is_of_node(dev->fwnode))
+ goto bypass_clk_reset_gpio;
+
+ dwmac->clk_tx = devm_clk_get(&pdev->dev, "tx");
+ if (IS_ERR(dwmac->clk_tx)) {
+ err = PTR_ERR(dwmac->clk_tx);
+ goto err;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_tx);
+ if (err < 0)
+ goto err;
+
+ dwmac->clk_gtx = devm_clk_get(&pdev->dev, "gtx");
+ if (IS_ERR(dwmac->clk_gtx)) {
+ err = PTR_ERR(dwmac->clk_gtx);
+ goto disable_tx;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_gtx);
+ if (err < 0)
+ goto disable_tx;
+
+ dwmac->clk_gtxc = devm_clk_get(&pdev->dev, "gtxc");
+ if (IS_ERR(dwmac->clk_gtxc)) {
+ err = PTR_ERR(dwmac->clk_gtxc);
+ goto disable_gtx;
+ }
+
+ err = clk_prepare_enable(dwmac->clk_gtxc);
+ if (err < 0)
+ goto disable_gtx;
+
+ err = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (err)
+ goto err;
+
+bypass_clk_reset_gpio:
+ plat_dat->fix_mac_speed = starfive_eth_fix_mac_speed;
+ plat_dat->init = NULL;
+ plat_dat->bsp_priv = dwmac;
+ return 0;
+
+disable_gtx:
+ clk_disable_unprepare(dwmac->clk_gtx);
+disable_tx:
+ clk_disable_unprepare(dwmac->clk_tx);
+err:
+ stmmac_remove_config_dt(pdev, plat_dat);
+ return err;
+}
+
+static int starfive_eth_plat_remove(struct platform_device *pdev)
+{
+ struct starfive_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
+
+ clk_disable_unprepare(dwmac->clk_gtxc);
+ clk_disable_unprepare(dwmac->clk_gtx);
+ clk_disable_unprepare(dwmac->clk_tx);
+
+ return 0;
+}
+
+static struct platform_driver starfive_eth_plat_driver = {
+ .probe = starfive_eth_plat_probe,
+ .remove = starfive_eth_plat_remove,
+ .driver = {
+ .name = "starfive-eth-plat",
+ .pm = &stmmac_pltfr_pm_ops,
+ .of_match_table = starfive_eth_plat_match,
+ },
+};
+
+module_platform_driver(starfive_eth_plat_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("StarFive DWMAC platform driver");
+