Skip to content

Commit 33a1a01

Browse files
xhackerustckuba-moo
authored andcommitted
net: stmmac: Add glue layer for T-HEAD TH1520 SoC
Add dwmac glue driver to support the DesignWare-based GMAC controllers on the T-HEAD TH1520 SoC. Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: Jisheng Zhang <[email protected]> Signed-off-by: Emil Renner Berthing <[email protected]> Signed-off-by: Drew Fustini <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent f920ce0 commit 33a1a01

File tree

4 files changed

+285
-0
lines changed

4 files changed

+285
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19848,6 +19848,7 @@ F: Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml
1984819848
F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml
1984919849
F: arch/riscv/boot/dts/thead/
1985019850
F: drivers/clk/thead/clk-th1520-ap.c
19851+
F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c
1985119852
F: include/dt-bindings/clock/thead,th1520-clk-ap.h
1985219853

1985319854
RNBD BLOCK DRIVERS

drivers/net/ethernet/stmicro/stmmac/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,16 @@ config DWMAC_SUN8I
228228
stmmac device driver. This driver is used for H3/A83T/A64
229229
EMAC ethernet controller.
230230

231+
config DWMAC_THEAD
232+
tristate "T-HEAD dwmac support"
233+
depends on OF && (ARCH_THEAD || COMPILE_TEST)
234+
help
235+
Support for ethernet controllers on T-HEAD RISC-V SoCs
236+
237+
This selects the T-HEAD platform specific glue layer support for
238+
the stmmac device driver. This driver is used for T-HEAD TH1520
239+
ethernet controller.
240+
231241
config DWMAC_IMX8
232242
tristate "NXP IMX8 DWMAC support"
233243
default ARCH_MXC

drivers/net/ethernet/stmicro/stmmac/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
2828
obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o
2929
obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
3030
obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
31+
obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o
3132
obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
3233
obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o
3334
obj-$(CONFIG_DWMAC_LOONGSON1) += dwmac-loongson1.o
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* T-HEAD DWMAC platform driver
4+
*
5+
* Copyright (C) 2021 Alibaba Group Holding Limited.
6+
* Copyright (C) 2023 Jisheng Zhang <[email protected]>
7+
*
8+
*/
9+
10+
#include <linux/bitfield.h>
11+
#include <linux/module.h>
12+
#include <linux/of.h>
13+
#include <linux/of_device.h>
14+
#include <linux/of_net.h>
15+
#include <linux/platform_device.h>
16+
17+
#include "stmmac_platform.h"
18+
19+
#define GMAC_CLK_EN 0x00
20+
#define GMAC_TX_CLK_EN BIT(1)
21+
#define GMAC_TX_CLK_N_EN BIT(2)
22+
#define GMAC_TX_CLK_OUT_EN BIT(3)
23+
#define GMAC_RX_CLK_EN BIT(4)
24+
#define GMAC_RX_CLK_N_EN BIT(5)
25+
#define GMAC_EPHY_REF_CLK_EN BIT(6)
26+
#define GMAC_RXCLK_DELAY_CTRL 0x04
27+
#define GMAC_RXCLK_BYPASS BIT(15)
28+
#define GMAC_RXCLK_INVERT BIT(14)
29+
#define GMAC_RXCLK_DELAY GENMASK(4, 0)
30+
#define GMAC_TXCLK_DELAY_CTRL 0x08
31+
#define GMAC_TXCLK_BYPASS BIT(15)
32+
#define GMAC_TXCLK_INVERT BIT(14)
33+
#define GMAC_TXCLK_DELAY GENMASK(4, 0)
34+
#define GMAC_PLLCLK_DIV 0x0c
35+
#define GMAC_PLLCLK_DIV_EN BIT(31)
36+
#define GMAC_PLLCLK_DIV_NUM GENMASK(7, 0)
37+
#define GMAC_GTXCLK_SEL 0x18
38+
#define GMAC_GTXCLK_SEL_PLL BIT(0)
39+
#define GMAC_INTF_CTRL 0x1c
40+
#define PHY_INTF_MASK BIT(0)
41+
#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1)
42+
#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0)
43+
#define GMAC_TXCLK_OEN 0x20
44+
#define TXCLK_DIR_MASK BIT(0)
45+
#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0)
46+
#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1)
47+
48+
#define GMAC_GMII_RGMII_RATE 125000000
49+
#define GMAC_MII_RATE 25000000
50+
51+
struct thead_dwmac {
52+
struct plat_stmmacenet_data *plat;
53+
void __iomem *apb_base;
54+
struct device *dev;
55+
};
56+
57+
static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat)
58+
{
59+
struct thead_dwmac *dwmac = plat->bsp_priv;
60+
u32 phyif;
61+
62+
switch (plat->mac_interface) {
63+
case PHY_INTERFACE_MODE_MII:
64+
phyif = PHY_INTF_MII_GMII;
65+
break;
66+
case PHY_INTERFACE_MODE_RGMII:
67+
case PHY_INTERFACE_MODE_RGMII_ID:
68+
case PHY_INTERFACE_MODE_RGMII_TXID:
69+
case PHY_INTERFACE_MODE_RGMII_RXID:
70+
phyif = PHY_INTF_RGMII;
71+
break;
72+
default:
73+
dev_err(dwmac->dev, "unsupported phy interface %d\n",
74+
plat->mac_interface);
75+
return -EINVAL;
76+
}
77+
78+
writel(phyif, dwmac->apb_base + GMAC_INTF_CTRL);
79+
return 0;
80+
}
81+
82+
static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat)
83+
{
84+
struct thead_dwmac *dwmac = plat->bsp_priv;
85+
u32 txclk_dir;
86+
87+
switch (plat->mac_interface) {
88+
case PHY_INTERFACE_MODE_MII:
89+
txclk_dir = TXCLK_DIR_INPUT;
90+
break;
91+
case PHY_INTERFACE_MODE_RGMII:
92+
case PHY_INTERFACE_MODE_RGMII_ID:
93+
case PHY_INTERFACE_MODE_RGMII_TXID:
94+
case PHY_INTERFACE_MODE_RGMII_RXID:
95+
txclk_dir = TXCLK_DIR_OUTPUT;
96+
break;
97+
default:
98+
dev_err(dwmac->dev, "unsupported phy interface %d\n",
99+
plat->mac_interface);
100+
return -EINVAL;
101+
}
102+
103+
writel(txclk_dir, dwmac->apb_base + GMAC_TXCLK_OEN);
104+
return 0;
105+
}
106+
107+
static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode)
108+
{
109+
struct plat_stmmacenet_data *plat;
110+
struct thead_dwmac *dwmac = priv;
111+
unsigned long rate;
112+
u32 div, reg;
113+
114+
plat = dwmac->plat;
115+
116+
switch (plat->mac_interface) {
117+
/* For MII, rxc/txc is provided by phy */
118+
case PHY_INTERFACE_MODE_MII:
119+
return;
120+
121+
case PHY_INTERFACE_MODE_RGMII:
122+
case PHY_INTERFACE_MODE_RGMII_ID:
123+
case PHY_INTERFACE_MODE_RGMII_RXID:
124+
case PHY_INTERFACE_MODE_RGMII_TXID:
125+
rate = clk_get_rate(plat->stmmac_clk);
126+
if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 ||
127+
rate % GMAC_MII_RATE != 0) {
128+
dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate);
129+
return;
130+
}
131+
132+
writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV);
133+
134+
switch (speed) {
135+
case SPEED_1000:
136+
div = rate / GMAC_GMII_RGMII_RATE;
137+
break;
138+
case SPEED_100:
139+
div = rate / GMAC_MII_RATE;
140+
break;
141+
case SPEED_10:
142+
div = rate * 10 / GMAC_MII_RATE;
143+
break;
144+
default:
145+
dev_err(dwmac->dev, "invalid speed %u\n", speed);
146+
return;
147+
}
148+
149+
reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) |
150+
FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div);
151+
writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV);
152+
break;
153+
default:
154+
dev_err(dwmac->dev, "unsupported phy interface %d\n",
155+
plat->mac_interface);
156+
return;
157+
}
158+
}
159+
160+
static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
161+
{
162+
struct thead_dwmac *dwmac = plat->bsp_priv;
163+
u32 reg;
164+
165+
switch (plat->mac_interface) {
166+
case PHY_INTERFACE_MODE_MII:
167+
reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN;
168+
break;
169+
170+
case PHY_INTERFACE_MODE_RGMII:
171+
case PHY_INTERFACE_MODE_RGMII_ID:
172+
case PHY_INTERFACE_MODE_RGMII_RXID:
173+
case PHY_INTERFACE_MODE_RGMII_TXID:
174+
/* use pll */
175+
writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL);
176+
reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN |
177+
GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN;
178+
break;
179+
180+
default:
181+
dev_err(dwmac->dev, "unsupported phy interface %d\n",
182+
plat->mac_interface);
183+
return -EINVAL;
184+
}
185+
186+
writel(reg, dwmac->apb_base + GMAC_CLK_EN);
187+
return 0;
188+
}
189+
190+
static int thead_dwmac_init(struct platform_device *pdev, void *priv)
191+
{
192+
struct thead_dwmac *dwmac = priv;
193+
unsigned int reg;
194+
int ret;
195+
196+
ret = thead_dwmac_set_phy_if(dwmac->plat);
197+
if (ret)
198+
return ret;
199+
200+
ret = thead_dwmac_set_txclk_dir(dwmac->plat);
201+
if (ret)
202+
return ret;
203+
204+
reg = readl(dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);
205+
reg &= ~(GMAC_RXCLK_DELAY);
206+
reg |= FIELD_PREP(GMAC_RXCLK_DELAY, 0);
207+
writel(reg, dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL);
208+
209+
reg = readl(dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);
210+
reg &= ~(GMAC_TXCLK_DELAY);
211+
reg |= FIELD_PREP(GMAC_TXCLK_DELAY, 0);
212+
writel(reg, dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL);
213+
214+
return thead_dwmac_enable_clk(dwmac->plat);
215+
}
216+
217+
static int thead_dwmac_probe(struct platform_device *pdev)
218+
{
219+
struct stmmac_resources stmmac_res;
220+
struct plat_stmmacenet_data *plat;
221+
struct thead_dwmac *dwmac;
222+
void __iomem *apb;
223+
int ret;
224+
225+
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
226+
if (ret)
227+
return dev_err_probe(&pdev->dev, ret,
228+
"failed to get resources\n");
229+
230+
plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
231+
if (IS_ERR(plat))
232+
return dev_err_probe(&pdev->dev, PTR_ERR(plat),
233+
"dt configuration failed\n");
234+
235+
dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
236+
if (!dwmac)
237+
return -ENOMEM;
238+
239+
apb = devm_platform_ioremap_resource(pdev, 1);
240+
if (IS_ERR(apb))
241+
return dev_err_probe(&pdev->dev, PTR_ERR(apb),
242+
"failed to remap gmac apb registers\n");
243+
244+
dwmac->dev = &pdev->dev;
245+
dwmac->plat = plat;
246+
dwmac->apb_base = apb;
247+
plat->bsp_priv = dwmac;
248+
plat->fix_mac_speed = thead_dwmac_fix_speed;
249+
plat->init = thead_dwmac_init;
250+
251+
return devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res);
252+
}
253+
254+
static const struct of_device_id thead_dwmac_match[] = {
255+
{ .compatible = "thead,th1520-gmac" },
256+
{ /* sentinel */ }
257+
};
258+
MODULE_DEVICE_TABLE(of, thead_dwmac_match);
259+
260+
static struct platform_driver thead_dwmac_driver = {
261+
.probe = thead_dwmac_probe,
262+
.driver = {
263+
.name = "thead-dwmac",
264+
.pm = &stmmac_pltfr_pm_ops,
265+
.of_match_table = thead_dwmac_match,
266+
},
267+
};
268+
module_platform_driver(thead_dwmac_driver);
269+
270+
MODULE_AUTHOR("Jisheng Zhang <[email protected]>");
271+
MODULE_AUTHOR("Drew Fustini <[email protected]>");
272+
MODULE_DESCRIPTION("T-HEAD DWMAC platform driver");
273+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)