-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: stmmac: Add glue layer for Loongson-1 SoC
This glue driver is created based on the arch-code implemented earlier with the platform-specific settings. Use syscon for SYSCON register access. And modify MAINTAINERS to add a new F: entry for this driver. Partially based on the previous work by Serge Semin. Signed-off-by: Keguang Zhang <keguang.zhang@gmail.com> Reviewed-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Keguang Zhang
authored and
David S. Miller
committed
Sep 16, 2023
1 parent
2af2107
commit d301c66
Showing
4 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Loongson-1 DWMAC glue layer | ||
* | ||
* Copyright (C) 2011-2023 Keguang Zhang <keguang.zhang@gmail.com> | ||
*/ | ||
|
||
#include <linux/mfd/syscon.h> | ||
#include <linux/module.h> | ||
#include <linux/of.h> | ||
#include <linux/phy.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/regmap.h> | ||
|
||
#include "stmmac.h" | ||
#include "stmmac_platform.h" | ||
|
||
#define LS1B_GMAC0_BASE (0x1fe10000) | ||
#define LS1B_GMAC1_BASE (0x1fe20000) | ||
|
||
/* Loongson-1 SYSCON Registers */ | ||
#define LS1X_SYSCON0 (0x0) | ||
#define LS1X_SYSCON1 (0x4) | ||
|
||
/* Loongson-1B SYSCON Register Bits */ | ||
#define GMAC1_USE_UART1 BIT(4) | ||
#define GMAC1_USE_UART0 BIT(3) | ||
|
||
#define GMAC1_SHUT BIT(13) | ||
#define GMAC0_SHUT BIT(12) | ||
|
||
#define GMAC1_USE_TXCLK BIT(3) | ||
#define GMAC0_USE_TXCLK BIT(2) | ||
#define GMAC1_USE_PWM23 BIT(1) | ||
#define GMAC0_USE_PWM01 BIT(0) | ||
|
||
/* Loongson-1C SYSCON Register Bits */ | ||
#define GMAC_SHUT BIT(6) | ||
|
||
#define PHY_INTF_SELI GENMASK(30, 28) | ||
#define PHY_INTF_MII FIELD_PREP(PHY_INTF_SELI, 0) | ||
#define PHY_INTF_RMII FIELD_PREP(PHY_INTF_SELI, 4) | ||
|
||
struct ls1x_dwmac { | ||
struct plat_stmmacenet_data *plat_dat; | ||
struct regmap *regmap; | ||
}; | ||
|
||
static int ls1b_dwmac_syscon_init(struct platform_device *pdev, void *priv) | ||
{ | ||
struct ls1x_dwmac *dwmac = priv; | ||
struct plat_stmmacenet_data *plat = dwmac->plat_dat; | ||
struct regmap *regmap = dwmac->regmap; | ||
struct resource *res; | ||
unsigned long reg_base; | ||
|
||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
if (!res) { | ||
dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); | ||
return -EINVAL; | ||
} | ||
reg_base = (unsigned long)res->start; | ||
|
||
if (reg_base == LS1B_GMAC0_BASE) { | ||
switch (plat->phy_interface) { | ||
case PHY_INTERFACE_MODE_RGMII_ID: | ||
regmap_update_bits(regmap, LS1X_SYSCON0, | ||
GMAC0_USE_TXCLK | GMAC0_USE_PWM01, | ||
0); | ||
break; | ||
case PHY_INTERFACE_MODE_MII: | ||
regmap_update_bits(regmap, LS1X_SYSCON0, | ||
GMAC0_USE_TXCLK | GMAC0_USE_PWM01, | ||
GMAC0_USE_TXCLK | GMAC0_USE_PWM01); | ||
break; | ||
default: | ||
dev_err(&pdev->dev, "Unsupported PHY mode %u\n", | ||
plat->phy_interface); | ||
return -EOPNOTSUPP; | ||
} | ||
|
||
regmap_update_bits(regmap, LS1X_SYSCON0, GMAC0_SHUT, 0); | ||
} else if (reg_base == LS1B_GMAC1_BASE) { | ||
regmap_update_bits(regmap, LS1X_SYSCON0, | ||
GMAC1_USE_UART1 | GMAC1_USE_UART0, | ||
GMAC1_USE_UART1 | GMAC1_USE_UART0); | ||
|
||
switch (plat->phy_interface) { | ||
case PHY_INTERFACE_MODE_RGMII_ID: | ||
regmap_update_bits(regmap, LS1X_SYSCON1, | ||
GMAC1_USE_TXCLK | GMAC1_USE_PWM23, | ||
0); | ||
|
||
break; | ||
case PHY_INTERFACE_MODE_MII: | ||
regmap_update_bits(regmap, LS1X_SYSCON1, | ||
GMAC1_USE_TXCLK | GMAC1_USE_PWM23, | ||
GMAC1_USE_TXCLK | GMAC1_USE_PWM23); | ||
break; | ||
default: | ||
dev_err(&pdev->dev, "Unsupported PHY mode %u\n", | ||
plat->phy_interface); | ||
return -EOPNOTSUPP; | ||
} | ||
|
||
regmap_update_bits(regmap, LS1X_SYSCON1, GMAC1_SHUT, 0); | ||
} else { | ||
dev_err(&pdev->dev, "Invalid Ethernet MAC base address %lx", | ||
reg_base); | ||
return -EINVAL; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int ls1c_dwmac_syscon_init(struct platform_device *pdev, void *priv) | ||
{ | ||
struct ls1x_dwmac *dwmac = priv; | ||
struct plat_stmmacenet_data *plat = dwmac->plat_dat; | ||
struct regmap *regmap = dwmac->regmap; | ||
|
||
switch (plat->phy_interface) { | ||
case PHY_INTERFACE_MODE_MII: | ||
regmap_update_bits(regmap, LS1X_SYSCON1, PHY_INTF_SELI, | ||
PHY_INTF_MII); | ||
break; | ||
case PHY_INTERFACE_MODE_RMII: | ||
regmap_update_bits(regmap, LS1X_SYSCON1, PHY_INTF_SELI, | ||
PHY_INTF_RMII); | ||
break; | ||
default: | ||
dev_err(&pdev->dev, "Unsupported PHY-mode %u\n", | ||
plat->phy_interface); | ||
return -EOPNOTSUPP; | ||
} | ||
|
||
regmap_update_bits(regmap, LS1X_SYSCON0, GMAC0_SHUT, 0); | ||
|
||
return 0; | ||
} | ||
|
||
static int ls1x_dwmac_probe(struct platform_device *pdev) | ||
{ | ||
struct plat_stmmacenet_data *plat_dat; | ||
struct stmmac_resources stmmac_res; | ||
struct regmap *regmap; | ||
struct ls1x_dwmac *dwmac; | ||
int (*init)(struct platform_device *pdev, void *priv); | ||
int ret; | ||
|
||
ret = stmmac_get_platform_resources(pdev, &stmmac_res); | ||
if (ret) | ||
return ret; | ||
|
||
/* Probe syscon */ | ||
regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | ||
"loongson,ls1-syscon"); | ||
if (IS_ERR(regmap)) | ||
return dev_err_probe(&pdev->dev, PTR_ERR(regmap), | ||
"Unable to find syscon\n"); | ||
|
||
init = of_device_get_match_data(&pdev->dev); | ||
if (!init) { | ||
dev_err(&pdev->dev, "No of match data provided\n"); | ||
return -EINVAL; | ||
} | ||
|
||
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); | ||
if (!dwmac) | ||
return -ENOMEM; | ||
|
||
plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); | ||
if (IS_ERR(plat_dat)) | ||
return dev_err_probe(&pdev->dev, PTR_ERR(plat_dat), | ||
"dt configuration failed\n"); | ||
|
||
plat_dat->bsp_priv = dwmac; | ||
plat_dat->init = init; | ||
dwmac->plat_dat = plat_dat; | ||
dwmac->regmap = regmap; | ||
|
||
return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); | ||
} | ||
|
||
static const struct of_device_id ls1x_dwmac_match[] = { | ||
{ | ||
.compatible = "loongson,ls1b-gmac", | ||
.data = &ls1b_dwmac_syscon_init, | ||
}, | ||
{ | ||
.compatible = "loongson,ls1c-emac", | ||
.data = &ls1c_dwmac_syscon_init, | ||
}, | ||
{ } | ||
}; | ||
MODULE_DEVICE_TABLE(of, ls1x_dwmac_match); | ||
|
||
static struct platform_driver ls1x_dwmac_driver = { | ||
.probe = ls1x_dwmac_probe, | ||
.driver = { | ||
.name = "loongson1-dwmac", | ||
.of_match_table = ls1x_dwmac_match, | ||
}, | ||
}; | ||
module_platform_driver(ls1x_dwmac_driver); | ||
|
||
MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>"); | ||
MODULE_DESCRIPTION("Loongson-1 DWMAC glue layer"); | ||
MODULE_LICENSE("GPL"); |