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