1// SPDX-License-Identifier: GPL-2.0-only
2#include <linux/platform_device.h>
3#include <linux/of.h>
4#include <linux/module.h>
5#include <linux/stmmac.h>
6#include <linux/clk.h>
7
8#include "stmmac_platform.h"
9
10static const char *const mgbe_clks[] = {
11	"rx-pcs", "tx", "tx-pcs", "mac-divider", "mac", "mgbe", "ptp-ref", "mac"
12};
13
14struct tegra_mgbe {
15	struct device *dev;
16
17	struct clk_bulk_data *clks;
18
19	struct reset_control *rst_mac;
20	struct reset_control *rst_pcs;
21
22	void __iomem *hv;
23	void __iomem *regs;
24	void __iomem *xpcs;
25
26	struct mii_bus *mii;
27};
28
29#define XPCS_WRAP_UPHY_RX_CONTROL 0x801c
30#define XPCS_WRAP_UPHY_RX_CONTROL_RX_SW_OVRD BIT(31)
31#define XPCS_WRAP_UPHY_RX_CONTROL_RX_PCS_PHY_RDY BIT(10)
32#define XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET BIT(9)
33#define XPCS_WRAP_UPHY_RX_CONTROL_RX_CAL_EN BIT(8)
34#define XPCS_WRAP_UPHY_RX_CONTROL_RX_SLEEP (BIT(7) | BIT(6))
35#define XPCS_WRAP_UPHY_RX_CONTROL_AUX_RX_IDDQ BIT(5)
36#define XPCS_WRAP_UPHY_RX_CONTROL_RX_IDDQ BIT(4)
37#define XPCS_WRAP_UPHY_RX_CONTROL_RX_DATA_EN BIT(0)
38#define XPCS_WRAP_UPHY_HW_INIT_CTRL 0x8020
39#define XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN BIT(0)
40#define XPCS_WRAP_UPHY_HW_INIT_CTRL_RX_EN BIT(2)
41#define XPCS_WRAP_UPHY_STATUS 0x8044
42#define XPCS_WRAP_UPHY_STATUS_TX_P_UP BIT(0)
43#define XPCS_WRAP_IRQ_STATUS 0x8050
44#define XPCS_WRAP_IRQ_STATUS_PCS_LINK_STS BIT(6)
45
46#define XPCS_REG_ADDR_SHIFT 10
47#define XPCS_REG_ADDR_MASK 0x1fff
48#define XPCS_ADDR 0x3fc
49
50#define MGBE_WRAP_COMMON_INTR_ENABLE	0x8704
51#define MAC_SBD_INTR			BIT(2)
52#define MGBE_WRAP_AXI_ASID0_CTRL	0x8400
53#define MGBE_SID			0x6
54
55static int __maybe_unused tegra_mgbe_suspend(struct device *dev)
56{
57	struct tegra_mgbe *mgbe = get_stmmac_bsp_priv(dev);
58	int err;
59
60	err = stmmac_suspend(dev);
61	if (err)
62		return err;
63
64	clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks);
65
66	return reset_control_assert(mgbe->rst_mac);
67}
68
69static int __maybe_unused tegra_mgbe_resume(struct device *dev)
70{
71	struct tegra_mgbe *mgbe = get_stmmac_bsp_priv(dev);
72	u32 value;
73	int err;
74
75	err = clk_bulk_prepare_enable(ARRAY_SIZE(mgbe_clks), mgbe->clks);
76	if (err < 0)
77		return err;
78
79	err = reset_control_deassert(mgbe->rst_mac);
80	if (err < 0)
81		return err;
82
83	/* Enable common interrupt at wrapper level */
84	writel(MAC_SBD_INTR, mgbe->regs + MGBE_WRAP_COMMON_INTR_ENABLE);
85
86	/* Program SID */
87	writel(MGBE_SID, mgbe->hv + MGBE_WRAP_AXI_ASID0_CTRL);
88
89	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_STATUS);
90	if ((value & XPCS_WRAP_UPHY_STATUS_TX_P_UP) == 0) {
91		value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL);
92		value |= XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN;
93		writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL);
94	}
95
96	err = readl_poll_timeout(mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL, value,
97				 (value & XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN) == 0,
98				 500, 500 * 2000);
99	if (err < 0) {
100		dev_err(mgbe->dev, "timeout waiting for TX lane to become enabled\n");
101		clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks);
102		return err;
103	}
104
105	err = stmmac_resume(dev);
106	if (err < 0)
107		clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks);
108
109	return err;
110}
111
112static int mgbe_uphy_lane_bringup_serdes_up(struct net_device *ndev, void *mgbe_data)
113{
114	struct tegra_mgbe *mgbe = (struct tegra_mgbe *)mgbe_data;
115	u32 value;
116	int err;
117
118	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
119	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_SW_OVRD;
120	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
121
122	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
123	value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_IDDQ;
124	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
125
126	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
127	value &= ~XPCS_WRAP_UPHY_RX_CONTROL_AUX_RX_IDDQ;
128	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
129
130	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
131	value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_SLEEP;
132	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
133
134	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
135	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_CAL_EN;
136	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
137
138	err = readl_poll_timeout(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL, value,
139				 (value & XPCS_WRAP_UPHY_RX_CONTROL_RX_CAL_EN) == 0,
140				 1000, 1000 * 2000);
141	if (err < 0) {
142		dev_err(mgbe->dev, "timeout waiting for RX calibration to become enabled\n");
143		return err;
144	}
145
146	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
147	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_DATA_EN;
148	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
149
150	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
151	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
152	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
153
154	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
155	value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_CDR_RESET;
156	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
157
158	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
159	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_PCS_PHY_RDY;
160	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
161
162	err = readl_poll_timeout(mgbe->xpcs + XPCS_WRAP_IRQ_STATUS, value,
163				 value & XPCS_WRAP_IRQ_STATUS_PCS_LINK_STS,
164				 500, 500 * 2000);
165	if (err < 0) {
166		dev_err(mgbe->dev, "timeout waiting for link to become ready\n");
167		return err;
168	}
169
170	/* clear status */
171	writel(value, mgbe->xpcs + XPCS_WRAP_IRQ_STATUS);
172
173	return 0;
174}
175
176static void mgbe_uphy_lane_bringup_serdes_down(struct net_device *ndev, void *mgbe_data)
177{
178	struct tegra_mgbe *mgbe = (struct tegra_mgbe *)mgbe_data;
179	u32 value;
180
181	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
182	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_SW_OVRD;
183	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
184
185	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
186	value &= ~XPCS_WRAP_UPHY_RX_CONTROL_RX_DATA_EN;
187	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
188
189	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
190	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_SLEEP;
191	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
192
193	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
194	value |= XPCS_WRAP_UPHY_RX_CONTROL_AUX_RX_IDDQ;
195	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
196
197	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
198	value |= XPCS_WRAP_UPHY_RX_CONTROL_RX_IDDQ;
199	writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_RX_CONTROL);
200}
201
202static int tegra_mgbe_probe(struct platform_device *pdev)
203{
204	struct plat_stmmacenet_data *plat;
205	struct stmmac_resources res;
206	struct tegra_mgbe *mgbe;
207	int irq, err, i;
208	u32 value;
209
210	mgbe = devm_kzalloc(&pdev->dev, sizeof(*mgbe), GFP_KERNEL);
211	if (!mgbe)
212		return -ENOMEM;
213
214	mgbe->dev = &pdev->dev;
215
216	memset(&res, 0, sizeof(res));
217
218	irq = platform_get_irq(pdev, 0);
219	if (irq < 0)
220		return irq;
221
222	mgbe->hv = devm_platform_ioremap_resource_byname(pdev, "hypervisor");
223	if (IS_ERR(mgbe->hv))
224		return PTR_ERR(mgbe->hv);
225
226	mgbe->regs = devm_platform_ioremap_resource_byname(pdev, "mac");
227	if (IS_ERR(mgbe->regs))
228		return PTR_ERR(mgbe->regs);
229
230	mgbe->xpcs = devm_platform_ioremap_resource_byname(pdev, "xpcs");
231	if (IS_ERR(mgbe->xpcs))
232		return PTR_ERR(mgbe->xpcs);
233
234	res.addr = mgbe->regs;
235	res.irq = irq;
236
237	mgbe->clks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(mgbe_clks),
238				  sizeof(*mgbe->clks), GFP_KERNEL);
239	if (!mgbe->clks)
240		return -ENOMEM;
241
242	for (i = 0; i <  ARRAY_SIZE(mgbe_clks); i++)
243		mgbe->clks[i].id = mgbe_clks[i];
244
245	err = devm_clk_bulk_get(mgbe->dev, ARRAY_SIZE(mgbe_clks), mgbe->clks);
246	if (err < 0)
247		return err;
248
249	err = clk_bulk_prepare_enable(ARRAY_SIZE(mgbe_clks), mgbe->clks);
250	if (err < 0)
251		return err;
252
253	/* Perform MAC reset */
254	mgbe->rst_mac = devm_reset_control_get(&pdev->dev, "mac");
255	if (IS_ERR(mgbe->rst_mac)) {
256		err = PTR_ERR(mgbe->rst_mac);
257		goto disable_clks;
258	}
259
260	err = reset_control_assert(mgbe->rst_mac);
261	if (err < 0)
262		goto disable_clks;
263
264	usleep_range(2000, 4000);
265
266	err = reset_control_deassert(mgbe->rst_mac);
267	if (err < 0)
268		goto disable_clks;
269
270	/* Perform PCS reset */
271	mgbe->rst_pcs = devm_reset_control_get(&pdev->dev, "pcs");
272	if (IS_ERR(mgbe->rst_pcs)) {
273		err = PTR_ERR(mgbe->rst_pcs);
274		goto disable_clks;
275	}
276
277	err = reset_control_assert(mgbe->rst_pcs);
278	if (err < 0)
279		goto disable_clks;
280
281	usleep_range(2000, 4000);
282
283	err = reset_control_deassert(mgbe->rst_pcs);
284	if (err < 0)
285		goto disable_clks;
286
287	plat = devm_stmmac_probe_config_dt(pdev, res.mac);
288	if (IS_ERR(plat)) {
289		err = PTR_ERR(plat);
290		goto disable_clks;
291	}
292
293	plat->has_xgmac = 1;
294	plat->flags |= STMMAC_FLAG_TSO_EN;
295	plat->pmt = 1;
296	plat->bsp_priv = mgbe;
297
298	if (!plat->mdio_node)
299		plat->mdio_node = of_get_child_by_name(pdev->dev.of_node, "mdio");
300
301	if (!plat->mdio_bus_data) {
302		plat->mdio_bus_data = devm_kzalloc(&pdev->dev, sizeof(*plat->mdio_bus_data),
303						   GFP_KERNEL);
304		if (!plat->mdio_bus_data) {
305			err = -ENOMEM;
306			goto disable_clks;
307		}
308	}
309
310	plat->mdio_bus_data->needs_reset = true;
311
312	value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_STATUS);
313	if ((value & XPCS_WRAP_UPHY_STATUS_TX_P_UP) == 0) {
314		value = readl(mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL);
315		value |= XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN;
316		writel(value, mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL);
317	}
318
319	err = readl_poll_timeout(mgbe->xpcs + XPCS_WRAP_UPHY_HW_INIT_CTRL, value,
320				 (value & XPCS_WRAP_UPHY_HW_INIT_CTRL_TX_EN) == 0,
321				 500, 500 * 2000);
322	if (err < 0) {
323		dev_err(mgbe->dev, "timeout waiting for TX lane to become enabled\n");
324		goto disable_clks;
325	}
326
327	plat->serdes_powerup = mgbe_uphy_lane_bringup_serdes_up;
328	plat->serdes_powerdown = mgbe_uphy_lane_bringup_serdes_down;
329
330	/* Tx FIFO Size - 128KB */
331	plat->tx_fifo_size = 131072;
332	/* Rx FIFO Size - 192KB */
333	plat->rx_fifo_size = 196608;
334
335	/* Enable common interrupt at wrapper level */
336	writel(MAC_SBD_INTR, mgbe->regs + MGBE_WRAP_COMMON_INTR_ENABLE);
337
338	/* Program SID */
339	writel(MGBE_SID, mgbe->hv + MGBE_WRAP_AXI_ASID0_CTRL);
340
341	plat->flags |= STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP;
342
343	err = stmmac_dvr_probe(&pdev->dev, plat, &res);
344	if (err < 0)
345		goto disable_clks;
346
347	return 0;
348
349disable_clks:
350	clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks);
351
352	return err;
353}
354
355static void tegra_mgbe_remove(struct platform_device *pdev)
356{
357	struct tegra_mgbe *mgbe = get_stmmac_bsp_priv(&pdev->dev);
358
359	clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks);
360
361	stmmac_pltfr_remove(pdev);
362}
363
364static const struct of_device_id tegra_mgbe_match[] = {
365	{ .compatible = "nvidia,tegra234-mgbe", },
366	{ }
367};
368MODULE_DEVICE_TABLE(of, tegra_mgbe_match);
369
370static SIMPLE_DEV_PM_OPS(tegra_mgbe_pm_ops, tegra_mgbe_suspend, tegra_mgbe_resume);
371
372static struct platform_driver tegra_mgbe_driver = {
373	.probe = tegra_mgbe_probe,
374	.remove_new = tegra_mgbe_remove,
375	.driver = {
376		.name = "tegra-mgbe",
377		.pm		= &tegra_mgbe_pm_ops,
378		.of_match_table = tegra_mgbe_match,
379	},
380};
381module_platform_driver(tegra_mgbe_driver);
382
383MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
384MODULE_DESCRIPTION("NVIDIA Tegra MGBE driver");
385MODULE_LICENSE("GPL");
386