1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2016 Joao Pinto <jpinto@synopsys.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/clk.h>
9*4882a593Smuzhiyun #include <linux/clk-provider.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
12*4882a593Smuzhiyun #include <linux/ethtool.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/iopoll.h>
15*4882a593Smuzhiyun #include <linux/ioport.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/of_device.h>
18*4882a593Smuzhiyun #include <linux/of_net.h>
19*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
20*4882a593Smuzhiyun #include <linux/platform_device.h>
21*4882a593Smuzhiyun #include <linux/reset.h>
22*4882a593Smuzhiyun #include <linux/stmmac.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "stmmac_platform.h"
25*4882a593Smuzhiyun #include "dwmac4.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct tegra_eqos {
28*4882a593Smuzhiyun struct device *dev;
29*4882a593Smuzhiyun void __iomem *regs;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct reset_control *rst;
32*4882a593Smuzhiyun struct clk *clk_master;
33*4882a593Smuzhiyun struct clk *clk_slave;
34*4882a593Smuzhiyun struct clk *clk_tx;
35*4882a593Smuzhiyun struct clk *clk_rx;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun struct gpio_desc *reset;
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
dwc_eth_dwmac_config_dt(struct platform_device * pdev,struct plat_stmmacenet_data * plat_dat)40*4882a593Smuzhiyun static int dwc_eth_dwmac_config_dt(struct platform_device *pdev,
41*4882a593Smuzhiyun struct plat_stmmacenet_data *plat_dat)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct device *dev = &pdev->dev;
44*4882a593Smuzhiyun u32 burst_map = 0;
45*4882a593Smuzhiyun u32 bit_index = 0;
46*4882a593Smuzhiyun u32 a_index = 0;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (!plat_dat->axi) {
49*4882a593Smuzhiyun plat_dat->axi = kzalloc(sizeof(struct stmmac_axi), GFP_KERNEL);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (!plat_dat->axi)
52*4882a593Smuzhiyun return -ENOMEM;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun plat_dat->axi->axi_lpi_en = device_property_read_bool(dev,
56*4882a593Smuzhiyun "snps,en-lpi");
57*4882a593Smuzhiyun if (device_property_read_u32(dev, "snps,write-requests",
58*4882a593Smuzhiyun &plat_dat->axi->axi_wr_osr_lmt)) {
59*4882a593Smuzhiyun /**
60*4882a593Smuzhiyun * Since the register has a reset value of 1, if property
61*4882a593Smuzhiyun * is missing, default to 1.
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun plat_dat->axi->axi_wr_osr_lmt = 1;
64*4882a593Smuzhiyun } else {
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun * If property exists, to keep the behavior from dwc_eth_qos,
67*4882a593Smuzhiyun * subtract one after parsing.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun plat_dat->axi->axi_wr_osr_lmt--;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (device_property_read_u32(dev, "snps,read-requests",
73*4882a593Smuzhiyun &plat_dat->axi->axi_rd_osr_lmt)) {
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun * Since the register has a reset value of 1, if property
76*4882a593Smuzhiyun * is missing, default to 1.
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun plat_dat->axi->axi_rd_osr_lmt = 1;
79*4882a593Smuzhiyun } else {
80*4882a593Smuzhiyun /**
81*4882a593Smuzhiyun * If property exists, to keep the behavior from dwc_eth_qos,
82*4882a593Smuzhiyun * subtract one after parsing.
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun plat_dat->axi->axi_rd_osr_lmt--;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun device_property_read_u32(dev, "snps,burst-map", &burst_map);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* converts burst-map bitmask to burst array */
89*4882a593Smuzhiyun for (bit_index = 0; bit_index < 7; bit_index++) {
90*4882a593Smuzhiyun if (burst_map & (1 << bit_index)) {
91*4882a593Smuzhiyun switch (bit_index) {
92*4882a593Smuzhiyun case 0:
93*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 4; break;
94*4882a593Smuzhiyun case 1:
95*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 8; break;
96*4882a593Smuzhiyun case 2:
97*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 16; break;
98*4882a593Smuzhiyun case 3:
99*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 32; break;
100*4882a593Smuzhiyun case 4:
101*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 64; break;
102*4882a593Smuzhiyun case 5:
103*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 128; break;
104*4882a593Smuzhiyun case 6:
105*4882a593Smuzhiyun plat_dat->axi->axi_blen[a_index] = 256; break;
106*4882a593Smuzhiyun default:
107*4882a593Smuzhiyun break;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun a_index++;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* dwc-qos needs GMAC4, AAL, TSO and PMT */
114*4882a593Smuzhiyun plat_dat->has_gmac4 = 1;
115*4882a593Smuzhiyun plat_dat->dma_cfg->aal = 1;
116*4882a593Smuzhiyun plat_dat->tso_en = 1;
117*4882a593Smuzhiyun plat_dat->pmt = 1;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
dwc_qos_probe(struct platform_device * pdev,struct plat_stmmacenet_data * plat_dat,struct stmmac_resources * stmmac_res)122*4882a593Smuzhiyun static void *dwc_qos_probe(struct platform_device *pdev,
123*4882a593Smuzhiyun struct plat_stmmacenet_data *plat_dat,
124*4882a593Smuzhiyun struct stmmac_resources *stmmac_res)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun int err;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun plat_dat->stmmac_clk = devm_clk_get(&pdev->dev, "apb_pclk");
129*4882a593Smuzhiyun if (IS_ERR(plat_dat->stmmac_clk)) {
130*4882a593Smuzhiyun dev_err(&pdev->dev, "apb_pclk clock not found.\n");
131*4882a593Smuzhiyun return ERR_CAST(plat_dat->stmmac_clk);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun err = clk_prepare_enable(plat_dat->stmmac_clk);
135*4882a593Smuzhiyun if (err < 0) {
136*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable apb_pclk clock: %d\n",
137*4882a593Smuzhiyun err);
138*4882a593Smuzhiyun return ERR_PTR(err);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun plat_dat->pclk = devm_clk_get(&pdev->dev, "phy_ref_clk");
142*4882a593Smuzhiyun if (IS_ERR(plat_dat->pclk)) {
143*4882a593Smuzhiyun dev_err(&pdev->dev, "phy_ref_clk clock not found.\n");
144*4882a593Smuzhiyun err = PTR_ERR(plat_dat->pclk);
145*4882a593Smuzhiyun goto disable;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun err = clk_prepare_enable(plat_dat->pclk);
149*4882a593Smuzhiyun if (err < 0) {
150*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n",
151*4882a593Smuzhiyun err);
152*4882a593Smuzhiyun goto disable;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return NULL;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun disable:
158*4882a593Smuzhiyun clk_disable_unprepare(plat_dat->stmmac_clk);
159*4882a593Smuzhiyun return ERR_PTR(err);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
dwc_qos_remove(struct platform_device * pdev)162*4882a593Smuzhiyun static int dwc_qos_remove(struct platform_device *pdev)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun struct net_device *ndev = platform_get_drvdata(pdev);
165*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun clk_disable_unprepare(priv->plat->pclk);
168*4882a593Smuzhiyun clk_disable_unprepare(priv->plat->stmmac_clk);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun #define SDMEMCOMPPADCTRL 0x8800
174*4882a593Smuzhiyun #define SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD BIT(31)
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun #define AUTO_CAL_CONFIG 0x8804
177*4882a593Smuzhiyun #define AUTO_CAL_CONFIG_START BIT(31)
178*4882a593Smuzhiyun #define AUTO_CAL_CONFIG_ENABLE BIT(29)
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun #define AUTO_CAL_STATUS 0x880c
181*4882a593Smuzhiyun #define AUTO_CAL_STATUS_ACTIVE BIT(31)
182*4882a593Smuzhiyun
tegra_eqos_fix_speed(void * priv,unsigned int speed)183*4882a593Smuzhiyun static void tegra_eqos_fix_speed(void *priv, unsigned int speed)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct tegra_eqos *eqos = priv;
186*4882a593Smuzhiyun unsigned long rate = 125000000;
187*4882a593Smuzhiyun bool needs_calibration = false;
188*4882a593Smuzhiyun u32 value;
189*4882a593Smuzhiyun int err;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun switch (speed) {
192*4882a593Smuzhiyun case SPEED_1000:
193*4882a593Smuzhiyun needs_calibration = true;
194*4882a593Smuzhiyun rate = 125000000;
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun case SPEED_100:
198*4882a593Smuzhiyun needs_calibration = true;
199*4882a593Smuzhiyun rate = 25000000;
200*4882a593Smuzhiyun break;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun case SPEED_10:
203*4882a593Smuzhiyun rate = 2500000;
204*4882a593Smuzhiyun break;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun default:
207*4882a593Smuzhiyun dev_err(eqos->dev, "invalid speed %u\n", speed);
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (needs_calibration) {
212*4882a593Smuzhiyun /* calibrate */
213*4882a593Smuzhiyun value = readl(eqos->regs + SDMEMCOMPPADCTRL);
214*4882a593Smuzhiyun value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
215*4882a593Smuzhiyun writel(value, eqos->regs + SDMEMCOMPPADCTRL);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun udelay(1);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun value = readl(eqos->regs + AUTO_CAL_CONFIG);
220*4882a593Smuzhiyun value |= AUTO_CAL_CONFIG_START | AUTO_CAL_CONFIG_ENABLE;
221*4882a593Smuzhiyun writel(value, eqos->regs + AUTO_CAL_CONFIG);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
224*4882a593Smuzhiyun value,
225*4882a593Smuzhiyun value & AUTO_CAL_STATUS_ACTIVE,
226*4882a593Smuzhiyun 1, 10);
227*4882a593Smuzhiyun if (err < 0) {
228*4882a593Smuzhiyun dev_err(eqos->dev, "calibration did not start\n");
229*4882a593Smuzhiyun goto failed;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun err = readl_poll_timeout_atomic(eqos->regs + AUTO_CAL_STATUS,
233*4882a593Smuzhiyun value,
234*4882a593Smuzhiyun (value & AUTO_CAL_STATUS_ACTIVE) == 0,
235*4882a593Smuzhiyun 20, 200);
236*4882a593Smuzhiyun if (err < 0) {
237*4882a593Smuzhiyun dev_err(eqos->dev, "calibration didn't finish\n");
238*4882a593Smuzhiyun goto failed;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun failed:
242*4882a593Smuzhiyun value = readl(eqos->regs + SDMEMCOMPPADCTRL);
243*4882a593Smuzhiyun value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD;
244*4882a593Smuzhiyun writel(value, eqos->regs + SDMEMCOMPPADCTRL);
245*4882a593Smuzhiyun } else {
246*4882a593Smuzhiyun value = readl(eqos->regs + AUTO_CAL_CONFIG);
247*4882a593Smuzhiyun value &= ~AUTO_CAL_CONFIG_ENABLE;
248*4882a593Smuzhiyun writel(value, eqos->regs + AUTO_CAL_CONFIG);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun err = clk_set_rate(eqos->clk_tx, rate);
252*4882a593Smuzhiyun if (err < 0)
253*4882a593Smuzhiyun dev_err(eqos->dev, "failed to set TX rate: %d\n", err);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
tegra_eqos_init(struct platform_device * pdev,void * priv)256*4882a593Smuzhiyun static int tegra_eqos_init(struct platform_device *pdev, void *priv)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun struct tegra_eqos *eqos = priv;
259*4882a593Smuzhiyun unsigned long rate;
260*4882a593Smuzhiyun u32 value;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun rate = clk_get_rate(eqos->clk_slave);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun value = (rate / 1000000) - 1;
265*4882a593Smuzhiyun writel(value, eqos->regs + GMAC_1US_TIC_COUNTER);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
tegra_eqos_probe(struct platform_device * pdev,struct plat_stmmacenet_data * data,struct stmmac_resources * res)270*4882a593Smuzhiyun static void *tegra_eqos_probe(struct platform_device *pdev,
271*4882a593Smuzhiyun struct plat_stmmacenet_data *data,
272*4882a593Smuzhiyun struct stmmac_resources *res)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun struct device *dev = &pdev->dev;
275*4882a593Smuzhiyun struct tegra_eqos *eqos;
276*4882a593Smuzhiyun int err;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun eqos = devm_kzalloc(&pdev->dev, sizeof(*eqos), GFP_KERNEL);
279*4882a593Smuzhiyun if (!eqos) {
280*4882a593Smuzhiyun err = -ENOMEM;
281*4882a593Smuzhiyun goto error;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun eqos->dev = &pdev->dev;
285*4882a593Smuzhiyun eqos->regs = res->addr;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun if (!is_of_node(dev->fwnode))
288*4882a593Smuzhiyun goto bypass_clk_reset_gpio;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun eqos->clk_master = devm_clk_get(&pdev->dev, "master_bus");
291*4882a593Smuzhiyun if (IS_ERR(eqos->clk_master)) {
292*4882a593Smuzhiyun err = PTR_ERR(eqos->clk_master);
293*4882a593Smuzhiyun goto error;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun err = clk_prepare_enable(eqos->clk_master);
297*4882a593Smuzhiyun if (err < 0)
298*4882a593Smuzhiyun goto error;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun eqos->clk_slave = devm_clk_get(&pdev->dev, "slave_bus");
301*4882a593Smuzhiyun if (IS_ERR(eqos->clk_slave)) {
302*4882a593Smuzhiyun err = PTR_ERR(eqos->clk_slave);
303*4882a593Smuzhiyun goto disable_master;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun data->stmmac_clk = eqos->clk_slave;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun err = clk_prepare_enable(eqos->clk_slave);
309*4882a593Smuzhiyun if (err < 0)
310*4882a593Smuzhiyun goto disable_master;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun eqos->clk_rx = devm_clk_get(&pdev->dev, "rx");
313*4882a593Smuzhiyun if (IS_ERR(eqos->clk_rx)) {
314*4882a593Smuzhiyun err = PTR_ERR(eqos->clk_rx);
315*4882a593Smuzhiyun goto disable_slave;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun err = clk_prepare_enable(eqos->clk_rx);
319*4882a593Smuzhiyun if (err < 0)
320*4882a593Smuzhiyun goto disable_slave;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun eqos->clk_tx = devm_clk_get(&pdev->dev, "tx");
323*4882a593Smuzhiyun if (IS_ERR(eqos->clk_tx)) {
324*4882a593Smuzhiyun err = PTR_ERR(eqos->clk_tx);
325*4882a593Smuzhiyun goto disable_rx;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun err = clk_prepare_enable(eqos->clk_tx);
329*4882a593Smuzhiyun if (err < 0)
330*4882a593Smuzhiyun goto disable_rx;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH);
333*4882a593Smuzhiyun if (IS_ERR(eqos->reset)) {
334*4882a593Smuzhiyun err = PTR_ERR(eqos->reset);
335*4882a593Smuzhiyun goto disable_tx;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun usleep_range(2000, 4000);
339*4882a593Smuzhiyun gpiod_set_value(eqos->reset, 0);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* MDIO bus was already reset just above */
342*4882a593Smuzhiyun data->mdio_bus_data->needs_reset = false;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun eqos->rst = devm_reset_control_get(&pdev->dev, "eqos");
345*4882a593Smuzhiyun if (IS_ERR(eqos->rst)) {
346*4882a593Smuzhiyun err = PTR_ERR(eqos->rst);
347*4882a593Smuzhiyun goto reset_phy;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun err = reset_control_assert(eqos->rst);
351*4882a593Smuzhiyun if (err < 0)
352*4882a593Smuzhiyun goto reset_phy;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun usleep_range(2000, 4000);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun err = reset_control_deassert(eqos->rst);
357*4882a593Smuzhiyun if (err < 0)
358*4882a593Smuzhiyun goto reset_phy;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun usleep_range(2000, 4000);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun bypass_clk_reset_gpio:
363*4882a593Smuzhiyun data->fix_mac_speed = tegra_eqos_fix_speed;
364*4882a593Smuzhiyun data->init = tegra_eqos_init;
365*4882a593Smuzhiyun data->bsp_priv = eqos;
366*4882a593Smuzhiyun data->sph_disable = 1;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun err = tegra_eqos_init(pdev, eqos);
369*4882a593Smuzhiyun if (err < 0)
370*4882a593Smuzhiyun goto reset;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun out:
373*4882a593Smuzhiyun return eqos;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun reset:
376*4882a593Smuzhiyun reset_control_assert(eqos->rst);
377*4882a593Smuzhiyun reset_phy:
378*4882a593Smuzhiyun gpiod_set_value(eqos->reset, 1);
379*4882a593Smuzhiyun disable_tx:
380*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_tx);
381*4882a593Smuzhiyun disable_rx:
382*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_rx);
383*4882a593Smuzhiyun disable_slave:
384*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_slave);
385*4882a593Smuzhiyun disable_master:
386*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_master);
387*4882a593Smuzhiyun error:
388*4882a593Smuzhiyun eqos = ERR_PTR(err);
389*4882a593Smuzhiyun goto out;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
tegra_eqos_remove(struct platform_device * pdev)392*4882a593Smuzhiyun static int tegra_eqos_remove(struct platform_device *pdev)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun struct tegra_eqos *eqos = get_stmmac_bsp_priv(&pdev->dev);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun reset_control_assert(eqos->rst);
397*4882a593Smuzhiyun gpiod_set_value(eqos->reset, 1);
398*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_tx);
399*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_rx);
400*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_slave);
401*4882a593Smuzhiyun clk_disable_unprepare(eqos->clk_master);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun return 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun struct dwc_eth_dwmac_data {
407*4882a593Smuzhiyun void *(*probe)(struct platform_device *pdev,
408*4882a593Smuzhiyun struct plat_stmmacenet_data *data,
409*4882a593Smuzhiyun struct stmmac_resources *res);
410*4882a593Smuzhiyun int (*remove)(struct platform_device *pdev);
411*4882a593Smuzhiyun };
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun static const struct dwc_eth_dwmac_data dwc_qos_data = {
414*4882a593Smuzhiyun .probe = dwc_qos_probe,
415*4882a593Smuzhiyun .remove = dwc_qos_remove,
416*4882a593Smuzhiyun };
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun static const struct dwc_eth_dwmac_data tegra_eqos_data = {
419*4882a593Smuzhiyun .probe = tegra_eqos_probe,
420*4882a593Smuzhiyun .remove = tegra_eqos_remove,
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
dwc_eth_dwmac_probe(struct platform_device * pdev)423*4882a593Smuzhiyun static int dwc_eth_dwmac_probe(struct platform_device *pdev)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun const struct dwc_eth_dwmac_data *data;
426*4882a593Smuzhiyun struct plat_stmmacenet_data *plat_dat;
427*4882a593Smuzhiyun struct stmmac_resources stmmac_res;
428*4882a593Smuzhiyun void *priv;
429*4882a593Smuzhiyun int ret;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun data = device_get_match_data(&pdev->dev);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun memset(&stmmac_res, 0, sizeof(struct stmmac_resources));
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /**
436*4882a593Smuzhiyun * Since stmmac_platform supports name IRQ only, basic platform
437*4882a593Smuzhiyun * resource initialization is done in the glue logic.
438*4882a593Smuzhiyun */
439*4882a593Smuzhiyun stmmac_res.irq = platform_get_irq(pdev, 0);
440*4882a593Smuzhiyun if (stmmac_res.irq < 0)
441*4882a593Smuzhiyun return stmmac_res.irq;
442*4882a593Smuzhiyun stmmac_res.wol_irq = stmmac_res.irq;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0);
445*4882a593Smuzhiyun if (IS_ERR(stmmac_res.addr))
446*4882a593Smuzhiyun return PTR_ERR(stmmac_res.addr);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
449*4882a593Smuzhiyun if (IS_ERR(plat_dat))
450*4882a593Smuzhiyun return PTR_ERR(plat_dat);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun priv = data->probe(pdev, plat_dat, &stmmac_res);
453*4882a593Smuzhiyun if (IS_ERR(priv)) {
454*4882a593Smuzhiyun ret = PTR_ERR(priv);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
457*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to probe subdriver: %d\n",
458*4882a593Smuzhiyun ret);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun goto remove_config;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun ret = dwc_eth_dwmac_config_dt(pdev, plat_dat);
464*4882a593Smuzhiyun if (ret)
465*4882a593Smuzhiyun goto remove;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
468*4882a593Smuzhiyun if (ret)
469*4882a593Smuzhiyun goto remove;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun return ret;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun remove:
474*4882a593Smuzhiyun data->remove(pdev);
475*4882a593Smuzhiyun remove_config:
476*4882a593Smuzhiyun stmmac_remove_config_dt(pdev, plat_dat);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun return ret;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
dwc_eth_dwmac_remove(struct platform_device * pdev)481*4882a593Smuzhiyun static int dwc_eth_dwmac_remove(struct platform_device *pdev)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun struct net_device *ndev = platform_get_drvdata(pdev);
484*4882a593Smuzhiyun struct stmmac_priv *priv = netdev_priv(ndev);
485*4882a593Smuzhiyun const struct dwc_eth_dwmac_data *data;
486*4882a593Smuzhiyun int err;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun data = device_get_match_data(&pdev->dev);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun err = stmmac_dvr_remove(&pdev->dev);
491*4882a593Smuzhiyun if (err < 0)
492*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to remove platform: %d\n", err);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun err = data->remove(pdev);
495*4882a593Smuzhiyun if (err < 0)
496*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to remove subdriver: %d\n", err);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun stmmac_remove_config_dt(pdev, priv->plat);
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun return err;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun static const struct of_device_id dwc_eth_dwmac_match[] = {
504*4882a593Smuzhiyun { .compatible = "snps,dwc-qos-ethernet-4.10", .data = &dwc_qos_data },
505*4882a593Smuzhiyun { .compatible = "nvidia,tegra186-eqos", .data = &tegra_eqos_data },
506*4882a593Smuzhiyun { }
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match);
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun static struct platform_driver dwc_eth_dwmac_driver = {
511*4882a593Smuzhiyun .probe = dwc_eth_dwmac_probe,
512*4882a593Smuzhiyun .remove = dwc_eth_dwmac_remove,
513*4882a593Smuzhiyun .driver = {
514*4882a593Smuzhiyun .name = "dwc-eth-dwmac",
515*4882a593Smuzhiyun .pm = &stmmac_pltfr_pm_ops,
516*4882a593Smuzhiyun .of_match_table = dwc_eth_dwmac_match,
517*4882a593Smuzhiyun },
518*4882a593Smuzhiyun };
519*4882a593Smuzhiyun module_platform_driver(dwc_eth_dwmac_driver);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun MODULE_AUTHOR("Joao Pinto <jpinto@synopsys.com>");
522*4882a593Smuzhiyun MODULE_DESCRIPTION("Synopsys DWC Ethernet Quality-of-Service v4.10a driver");
523*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
524