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/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");