Linux Audio

Check our new training course

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