net: stmmac: multiple queues dt configuration
[linux-2.6-block.git] / drivers / net / ethernet / stmicro / stmmac / stmmac_platform.c
CommitLineData
bfab27a1
GC
1/*******************************************************************************
2 This contains the functions to handle the platform driver.
3
4 Copyright (C) 2007-2011 STMicroelectronics Ltd
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
9
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
bfab27a1
GC
15 The full GNU General Public License is included in this distribution in
16 the file called "COPYING".
17
18 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
19*******************************************************************************/
20
21#include <linux/platform_device.h>
f0e9fc50 22#include <linux/module.h>
bfab27a1 23#include <linux/io.h>
6a228452
SR
24#include <linux/of.h>
25#include <linux/of_net.h>
022066f5 26#include <linux/of_device.h>
5790cf3c 27#include <linux/of_mdio.h>
f10f9fb2 28
bfab27a1 29#include "stmmac.h"
f10f9fb2 30#include "stmmac_platform.h"
bfab27a1 31
6a228452 32#ifdef CONFIG_OF
3b57de95 33
732fdf0e
GC
34/**
35 * dwmac1000_validate_mcast_bins - validates the number of Multicast filter bins
36 * @mcast_bins: Multicast filtering bins
37 * Description:
38 * this function validates the number of Multicast filtering bins specified
3b57de95
VB
39 * by the configuration through the device tree. The Synopsys GMAC supports
40 * 64 bins, 128 bins, or 256 bins. "bins" refer to the division of CRC
41 * number space. 64 bins correspond to 6 bits of the CRC, 128 corresponds
42 * to 7 bits, and 256 refers to 8 bits of the CRC. Any other setting is
43 * invalid and will cause the filtering algorithm to use Multicast
44 * promiscuous mode.
45 */
46static int dwmac1000_validate_mcast_bins(int mcast_bins)
47{
48 int x = mcast_bins;
49
50 switch (x) {
51 case HASH_TABLE_SIZE:
52 case 128:
53 case 256:
54 break;
55 default:
56 x = 0;
57 pr_info("Hash table entries set to unexpected value %d",
58 mcast_bins);
59 break;
60 }
61 return x;
62}
63
732fdf0e
GC
64/**
65 * dwmac1000_validate_ucast_entries - validate the Unicast address entries
66 * @ucast_entries: number of Unicast address entries
67 * Description:
68 * This function validates the number of Unicast address entries supported
3b57de95
VB
69 * by a particular Synopsys 10/100/1000 controller. The Synopsys controller
70 * supports 1, 32, 64, or 128 Unicast filter entries for it's Unicast filter
71 * logic. This function validates a valid, supported configuration is
72 * selected, and defaults to 1 Unicast address if an unsupported
73 * configuration is selected.
74 */
75static int dwmac1000_validate_ucast_entries(int ucast_entries)
76{
77 int x = ucast_entries;
78
79 switch (x) {
80 case 1:
81 case 32:
82 case 64:
83 case 128:
84 break;
85 default:
86 x = 1;
87 pr_info("Unicast table entries set to unexpected value %d\n",
88 ucast_entries);
89 break;
90 }
91 return x;
92}
93
afea0365
GC
94/**
95 * stmmac_axi_setup - parse DT parameters for programming the AXI register
96 * @pdev: platform device
97 * @priv: driver private struct.
98 * Description:
99 * if required, from device-tree the AXI internal register can be tuned
100 * by using platform parameters.
101 */
102static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
103{
104 struct device_node *np;
105 struct stmmac_axi *axi;
106
107 np = of_parse_phandle(pdev->dev.of_node, "snps,axi-config", 0);
108 if (!np)
109 return NULL;
110
64f48e59 111 axi = devm_kzalloc(&pdev->dev, sizeof(*axi), GFP_KERNEL);
4613b279
PC
112 if (!axi) {
113 of_node_put(np);
afea0365 114 return ERR_PTR(-ENOMEM);
4613b279 115 }
afea0365
GC
116
117 axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
118 axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
119 axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
afea0365
GC
120 axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
121 axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
122 axi->axi_rb = of_property_read_bool(np, "snps,axi_rb");
123
6b3374cb
NC
124 if (of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt))
125 axi->axi_wr_osr_lmt = 1;
126 if (of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt))
127 axi->axi_rd_osr_lmt = 1;
afea0365 128 of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
4613b279 129 of_node_put(np);
afea0365
GC
130
131 return axi;
132}
133
d976a525
JP
134/**
135 * stmmac_mtl_setup - parse DT parameters for multiple queues configuration
136 * @pdev: platform device
137 */
138static void stmmac_mtl_setup(struct platform_device *pdev,
139 struct plat_stmmacenet_data *plat)
140{
141 struct device_node *q_node;
142 struct device_node *rx_node;
143 struct device_node *tx_node;
144 u8 queue = 0;
145
146 rx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-rx-config", 0);
147 if (!rx_node)
148 return;
149
150 tx_node = of_parse_phandle(pdev->dev.of_node, "snps,mtl-tx-config", 0);
151 if (!tx_node) {
152 of_node_put(rx_node);
153 return;
154 }
155
156 /* Processing RX queues common config */
157 if (of_property_read_u8(rx_node, "snps,rx-queues-to-use",
158 &plat->rx_queues_to_use))
159 plat->rx_queues_to_use = 1;
160
161 if (of_property_read_bool(rx_node, "snps,rx-sched-sp"))
162 plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
163 else if (of_property_read_bool(rx_node, "snps,rx-sched-wsp"))
164 plat->rx_sched_algorithm = MTL_RX_ALGORITHM_WSP;
165 else
166 plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
167
168 /* Processing individual RX queue config */
169 for_each_child_of_node(rx_node, q_node) {
170 if (queue >= plat->rx_queues_to_use)
171 break;
172
173 if (of_property_read_bool(q_node, "snps,dcb-algorithm"))
174 plat->rx_queues_cfg[queue].mode_to_use = MTL_RX_DCB;
175 else if (of_property_read_bool(q_node, "snps,avb-algorithm"))
176 plat->rx_queues_cfg[queue].mode_to_use = MTL_RX_AVB;
177 else
178 plat->rx_queues_cfg[queue].mode_to_use = MTL_RX_DCB;
179
180 if (of_property_read_u8(q_node, "snps,map-to-dma-channel",
181 &plat->rx_queues_cfg[queue].chan))
182 plat->rx_queues_cfg[queue].chan = queue;
183 /* TODO: Dynamic mapping to be included in the future */
184
185 queue++;
186 }
187
188 /* Processing TX queues common config */
189 if (of_property_read_u8(tx_node, "snps,tx-queues-to-use",
190 &plat->tx_queues_to_use))
191 plat->tx_queues_to_use = 1;
192
193 if (of_property_read_bool(tx_node, "snps,tx-sched-wrr"))
194 plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
195 else if (of_property_read_bool(tx_node, "snps,tx-sched-wfq"))
196 plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WFQ;
197 else if (of_property_read_bool(tx_node, "snps,tx-sched-dwrr"))
198 plat->tx_sched_algorithm = MTL_TX_ALGORITHM_DWRR;
199 else if (of_property_read_bool(tx_node, "snps,tx-sched-sp"))
200 plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
201 else
202 plat->tx_sched_algorithm = MTL_TX_ALGORITHM_SP;
203
204 queue = 0;
205
206 /* Processing individual TX queue config */
207 for_each_child_of_node(tx_node, q_node) {
208 if (queue >= plat->tx_queues_to_use)
209 break;
210
211 if (of_property_read_u8(q_node, "snps,weight",
212 &plat->tx_queues_cfg[queue].weight))
213 plat->tx_queues_cfg[queue].weight = 0x10 + queue;
214
215 queue++;
216 }
217
218 of_node_put(rx_node);
219 of_node_put(tx_node);
220 of_node_put(q_node);
221}
222
a7657f12
GC
223/**
224 * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
225 * @plat: driver data platform structure
226 * @np: device tree node
227 * @dev: device pointer
228 * Description:
229 * The mdio bus will be allocated in case of a phy transceiver is on board;
230 * it will be NULL if the fixed-link is configured.
231 * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
232 * in any case (for DSA, mdio must be registered even if fixed-link).
233 * The table below sums the supported configurations:
234 * -------------------------------
235 * snps,phy-addr | Y
236 * -------------------------------
237 * phy-handle | Y
238 * -------------------------------
239 * fixed-link | N
240 * -------------------------------
241 * snps,dwmac-mdio |
242 * even if | Y
243 * fixed-link |
244 * -------------------------------
245 *
246 * It returns 0 in case of success otherwise -ENODEV.
247 */
248static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
249 struct device_node *np, struct device *dev)
250{
251 bool mdio = true;
252
253 /* If phy-handle property is passed from DT, use it as the PHY */
254 plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
255 if (plat->phy_node)
256 dev_dbg(dev, "Found phy-handle subnode\n");
257
258 /* If phy-handle is not specified, check if we have a fixed-phy */
259 if (!plat->phy_node && of_phy_is_fixed_link(np)) {
260 if ((of_phy_register_fixed_link(np) < 0))
261 return -ENODEV;
262
263 dev_dbg(dev, "Found fixed-link subnode\n");
264 plat->phy_node = of_node_get(np);
265 mdio = false;
266 }
267
d8256121 268 /* exception for dwmac-dwc-qos-eth glue logic */
269 if (of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) {
270 plat->mdio_node = of_get_child_by_name(np, "mdio");
271 } else {
272 /**
273 * If snps,dwmac-mdio is passed from DT, always register
274 * the MDIO
275 */
276 for_each_child_of_node(np, plat->mdio_node) {
277 if (of_device_is_compatible(plat->mdio_node,
278 "snps,dwmac-mdio"))
dbeaa8c2 279 break;
d8256121 280 }
a7657f12
GC
281 }
282
283 if (plat->mdio_node) {
284 dev_dbg(dev, "Found MDIO subnode\n");
285 mdio = true;
286 }
287
288 if (mdio)
289 plat->mdio_bus_data =
290 devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
291 GFP_KERNEL);
292 return 0;
293}
294
732fdf0e
GC
295/**
296 * stmmac_probe_config_dt - parse device-tree driver parameters
297 * @pdev: platform_device structure
732fdf0e
GC
298 * @mac: MAC address to use
299 * Description:
300 * this function is to read the driver parameters from device-tree and
301 * set some private fields that will be used by the main at runtime.
302 */
402dae0b 303struct plat_stmmacenet_data *
b0003ead 304stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
6a228452
SR
305{
306 struct device_node *np = pdev->dev.of_node;
4ed2d8fc 307 struct plat_stmmacenet_data *plat;
25c83b5c 308 struct stmmac_dma_cfg *dma_cfg;
6a228452 309
4ed2d8fc
JE
310 plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
311 if (!plat)
b0003ead 312 return ERR_PTR(-ENOMEM);
4ed2d8fc 313
6a228452
SR
314 *mac = of_get_mac_address(np);
315 plat->interface = of_get_phy_mode(np);
25c83b5c 316
9cbadf09
SK
317 /* Get max speed of operation from device tree */
318 if (of_property_read_u32(np, "max-speed", &plat->max_speed))
319 plat->max_speed = -1;
320
25c83b5c
SK
321 plat->bus_id = of_alias_get_id(np, "ethernet");
322 if (plat->bus_id < 0)
323 plat->bus_id = 0;
324
436f7ecd
CYT
325 /* Default to phy auto-detection */
326 plat->phy_addr = -1;
327
328 /* "snps,phy-addr" is not a standard property. Mark it as deprecated
329 * and warn of its use. Remove this when phy node support is added.
330 */
331 if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
332 dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
25c83b5c 333
a7657f12
GC
334 /* To Configure PHY by using all device-tree supported properties */
335 if (stmmac_dt_phy(plat, np, &pdev->dev))
336 return ERR_PTR(-ENODEV);
8c2a7a5d 337
e7877f52
VB
338 of_property_read_u32(np, "tx-fifo-depth", &plat->tx_fifo_size);
339
340 of_property_read_u32(np, "rx-fifo-depth", &plat->rx_fifo_size);
341
8c2a7a5d
GC
342 plat->force_sf_dma_mode =
343 of_property_read_bool(np, "snps,force_sf_dma_mode");
6aedb8c0 344
b4b7b772 345 plat->en_tx_lpi_clockgating =
346 of_property_read_bool(np, "snps,en-tx-lpi-clockgating");
347
2618abb7
VB
348 /* Set the maxmtu to a default of JUMBO_LEN in case the
349 * parameter is not present in the device tree.
350 */
351 plat->maxmtu = JUMBO_LEN;
352
4ed2d8fc
JE
353 /* Set default value for multicast hash bins */
354 plat->multicast_filter_bins = HASH_TABLE_SIZE;
355
356 /* Set default value for unicast filter entries */
357 plat->unicast_filter_entries = 1;
358
6a228452
SR
359 /*
360 * Currently only the properties needed on SPEAr600
361 * are provided. All other properties should be added
362 * once needed on other platforms.
363 */
84c9f8c4 364 if (of_device_is_compatible(np, "st,spear600-gmac") ||
f9a09687 365 of_device_is_compatible(np, "snps,dwmac-3.50a") ||
84c9f8c4
DN
366 of_device_is_compatible(np, "snps,dwmac-3.70a") ||
367 of_device_is_compatible(np, "snps,dwmac")) {
2618abb7
VB
368 /* Note that the max-frame-size parameter as defined in the
369 * ePAPR v1.1 spec is defined as max-frame-size, it's
370 * actually used as the IEEE definition of MAC Client
371 * data, or MTU. The ePAPR specification is confusing as
372 * the definition is max-frame-size, but usage examples
373 * are clearly MTUs
374 */
375 of_property_read_u32(np, "max-frame-size", &plat->maxmtu);
3b57de95
VB
376 of_property_read_u32(np, "snps,multicast-filter-bins",
377 &plat->multicast_filter_bins);
378 of_property_read_u32(np, "snps,perfect-filter-entries",
379 &plat->unicast_filter_entries);
380 plat->unicast_filter_entries = dwmac1000_validate_ucast_entries(
381 plat->unicast_filter_entries);
382 plat->multicast_filter_bins = dwmac1000_validate_mcast_bins(
383 plat->multicast_filter_bins);
6a228452
SR
384 plat->has_gmac = 1;
385 plat->pmt = 1;
386 }
387
ee2ae1ed
AT
388 if (of_device_is_compatible(np, "snps,dwmac-4.00") ||
389 of_device_is_compatible(np, "snps,dwmac-4.10a")) {
390 plat->has_gmac4 = 1;
7cc99fd2 391 plat->has_gmac = 0;
ee2ae1ed
AT
392 plat->pmt = 1;
393 plat->tso_en = of_property_read_bool(np, "snps,tso");
394 }
395
25c83b5c
SK
396 if (of_device_is_compatible(np, "snps,dwmac-3.610") ||
397 of_device_is_compatible(np, "snps,dwmac-3.710")) {
398 plat->enh_desc = 1;
399 plat->bugged_jumbo = 1;
400 plat->force_sf_dma_mode = 1;
401 }
402
a332e2fa
NC
403 dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
404 GFP_KERNEL);
405 if (!dma_cfg) {
406 stmmac_remove_config_dt(pdev, plat);
407 return ERR_PTR(-ENOMEM);
64c3b252 408 }
a332e2fa
NC
409 plat->dma_cfg = dma_cfg;
410
411 of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
412 if (!dma_cfg->pbl)
413 dma_cfg->pbl = DEFAULT_DMA_PBL;
89caaa2d
NC
414 of_property_read_u32(np, "snps,txpbl", &dma_cfg->txpbl);
415 of_property_read_u32(np, "snps,rxpbl", &dma_cfg->rxpbl);
4022d039 416 dma_cfg->pblx8 = !of_property_read_bool(np, "snps,no-pbl-x8");
a332e2fa
NC
417
418 dma_cfg->aal = of_property_read_bool(np, "snps,aal");
419 dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
420 dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
421
e2a240c7
SZ
422 plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
423 if (plat->force_thresh_dma_mode) {
424 plat->force_sf_dma_mode = 0;
425 pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
356f9e74 426 }
25c83b5c 427
02e57b9d
GC
428 of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed);
429
afea0365
GC
430 plat->axi = stmmac_axi_setup(pdev);
431
d976a525
JP
432 stmmac_mtl_setup(pdev, plat);
433
f573c0b9 434 /* clock setup */
435 plat->stmmac_clk = devm_clk_get(&pdev->dev,
436 STMMAC_RESOURCE_NAME);
437 if (IS_ERR(plat->stmmac_clk)) {
438 dev_warn(&pdev->dev, "Cannot get CSR clock\n");
439 plat->stmmac_clk = NULL;
440 }
441 clk_prepare_enable(plat->stmmac_clk);
442
443 plat->pclk = devm_clk_get(&pdev->dev, "pclk");
444 if (IS_ERR(plat->pclk)) {
445 if (PTR_ERR(plat->pclk) == -EPROBE_DEFER)
446 goto error_pclk_get;
447
448 plat->pclk = NULL;
449 }
450 clk_prepare_enable(plat->pclk);
451
452 /* Fall-back to main clock in case of no PTP ref is passed */
9fbb9dd8 453 plat->clk_ptp_ref = devm_clk_get(&pdev->dev, "ptp_ref");
f573c0b9 454 if (IS_ERR(plat->clk_ptp_ref)) {
455 plat->clk_ptp_rate = clk_get_rate(plat->stmmac_clk);
456 plat->clk_ptp_ref = NULL;
457 dev_warn(&pdev->dev, "PTP uses main clock\n");
458 } else {
f573c0b9 459 plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref);
fd3984e6 460 dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate);
f573c0b9 461 }
462
463 plat->stmmac_rst = devm_reset_control_get(&pdev->dev,
464 STMMAC_RESOURCE_NAME);
465 if (IS_ERR(plat->stmmac_rst)) {
466 if (PTR_ERR(plat->stmmac_rst) == -EPROBE_DEFER)
467 goto error_hw_init;
468
469 dev_info(&pdev->dev, "no reset control found\n");
470 plat->stmmac_rst = NULL;
471 }
472
b0003ead 473 return plat;
f573c0b9 474
475error_hw_init:
476 clk_disable_unprepare(plat->pclk);
477error_pclk_get:
478 clk_disable_unprepare(plat->stmmac_clk);
479
480 return ERR_PTR(-EPROBE_DEFER);
6a228452 481}
d2ed0a77
JH
482
483/**
484 * stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt()
485 * @pdev: platform_device structure
486 * @plat: driver data platform structure
487 *
488 * Release resources claimed by stmmac_probe_config_dt().
489 */
490void stmmac_remove_config_dt(struct platform_device *pdev,
491 struct plat_stmmacenet_data *plat)
492{
493 struct device_node *np = pdev->dev.of_node;
494
495 if (of_phy_is_fixed_link(np))
496 of_phy_deregister_fixed_link(np);
497 of_node_put(plat->phy_node);
a249708b 498 of_node_put(plat->mdio_node);
d2ed0a77 499}
6a228452 500#else
402dae0b 501struct plat_stmmacenet_data *
b0003ead 502stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
6a228452 503{
b2a8315a 504 return ERR_PTR(-EINVAL);
6a228452 505}
d2ed0a77
JH
506
507void stmmac_remove_config_dt(struct platform_device *pdev,
508 struct plat_stmmacenet_data *plat)
509{
510}
6a228452 511#endif /* CONFIG_OF */
402dae0b 512EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
d2ed0a77 513EXPORT_SYMBOL_GPL(stmmac_remove_config_dt);
6a228452 514
402dae0b
JE
515int stmmac_get_platform_resources(struct platform_device *pdev,
516 struct stmmac_resources *stmmac_res)
bfab27a1 517{
bfab27a1 518 struct resource *res;
e56788cf 519
f396cb01 520 memset(stmmac_res, 0, sizeof(*stmmac_res));
8f02d8da
AB
521
522 /* Get IRQ information early to have an ability to ask for deferred
523 * probe if needed before we went too far with resource allocation.
524 */
f396cb01
JE
525 stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
526 if (stmmac_res->irq < 0) {
527 if (stmmac_res->irq != -EPROBE_DEFER) {
528 dev_err(&pdev->dev,
8f02d8da
AB
529 "MAC IRQ configuration information not found\n");
530 }
f396cb01 531 return stmmac_res->irq;
8f02d8da
AB
532 }
533
534 /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
535 * The external wake up irq can be passed through the platform code
536 * named as "eth_wake_irq"
537 *
538 * In case the wake up interrupt is not passed from the platform
539 * so the driver will continue to use the mac irq (ndev->irq)
540 */
f396cb01
JE
541 stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
542 if (stmmac_res->wol_irq < 0) {
543 if (stmmac_res->wol_irq == -EPROBE_DEFER)
8f02d8da 544 return -EPROBE_DEFER;
f396cb01 545 stmmac_res->wol_irq = stmmac_res->irq;
8f02d8da
AB
546 }
547
f396cb01
JE
548 stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
549 if (stmmac_res->lpi_irq == -EPROBE_DEFER)
8f02d8da 550 return -EPROBE_DEFER;
bfab27a1
GC
551
552 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
f396cb01 553 stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
f396cb01 554
a04c0aef 555 return PTR_ERR_OR_ZERO(stmmac_res->addr);
f396cb01 556}
402dae0b 557EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
f396cb01 558
bfab27a1
GC
559/**
560 * stmmac_pltfr_remove
561 * @pdev: platform device pointer
562 * Description: this function calls the main to free the net resources
563 * and calls the platforms hook and release the resources (e.g. mem).
564 */
902b1607 565int stmmac_pltfr_remove(struct platform_device *pdev)
bfab27a1
GC
566{
567 struct net_device *ndev = platform_get_drvdata(pdev);
568 struct stmmac_priv *priv = netdev_priv(ndev);
d2ed0a77 569 struct plat_stmmacenet_data *plat = priv->plat;
f4e7bd81 570 int ret = stmmac_dvr_remove(&pdev->dev);
bfab27a1 571
d2ed0a77
JH
572 if (plat->exit)
573 plat->exit(pdev, plat->bsp_priv);
574
575 stmmac_remove_config_dt(pdev, plat);
938dfdaa 576
bfab27a1
GC
577 return ret;
578}
902b1607 579EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
bfab27a1 580
b2e2f0c7 581#ifdef CONFIG_PM_SLEEP
732fdf0e
GC
582/**
583 * stmmac_pltfr_suspend
584 * @dev: device pointer
585 * Description: this function is invoked when suspend the driver and it direcly
586 * call the main suspend function and then, if required, on some platform, it
587 * can call an exit helper.
588 */
bfab27a1 589static int stmmac_pltfr_suspend(struct device *dev)
bfab27a1 590{
3256251f 591 int ret;
bfab27a1 592 struct net_device *ndev = dev_get_drvdata(dev);
33a23e22 593 struct stmmac_priv *priv = netdev_priv(ndev);
3256251f 594 struct platform_device *pdev = to_platform_device(dev);
bfab27a1 595
f4e7bd81 596 ret = stmmac_suspend(dev);
5a3c7805 597 if (priv->plat->exit)
938dfdaa 598 priv->plat->exit(pdev, priv->plat->bsp_priv);
3256251f
FV
599
600 return ret;
bfab27a1
GC
601}
602
732fdf0e
GC
603/**
604 * stmmac_pltfr_resume
605 * @dev: device pointer
606 * Description: this function is invoked when resume the driver before calling
607 * the main resume function, on some platforms, it can call own init helper
608 * if required.
609 */
33a23e22 610static int stmmac_pltfr_resume(struct device *dev)
bfab27a1
GC
611{
612 struct net_device *ndev = dev_get_drvdata(dev);
33a23e22 613 struct stmmac_priv *priv = netdev_priv(ndev);
3256251f
FV
614 struct platform_device *pdev = to_platform_device(dev);
615
5a3c7805 616 if (priv->plat->init)
938dfdaa 617 priv->plat->init(pdev, priv->plat->bsp_priv);
bfab27a1 618
f4e7bd81 619 return stmmac_resume(dev);
bfab27a1 620}
b2e2f0c7 621#endif /* CONFIG_PM_SLEEP */
bfab27a1 622
902b1607
JE
623SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
624 stmmac_pltfr_resume);
625EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
ea111545
JE
626
627MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
628MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
629MODULE_LICENSE("GPL");