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