linux/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2018 MediaTek Inc.
   4 */
   5#include <linux/bitfield.h>
   6#include <linux/io.h>
   7#include <linux/mfd/syscon.h>
   8#include <linux/module.h>
   9#include <linux/of.h>
  10#include <linux/of_device.h>
  11#include <linux/of_net.h>
  12#include <linux/pm_runtime.h>
  13#include <linux/regmap.h>
  14#include <linux/stmmac.h>
  15
  16#include "stmmac.h"
  17#include "stmmac_platform.h"
  18
  19/* Peri Configuration register for mt2712 */
  20#define PERI_ETH_PHY_INTF_SEL   0x418
  21#define PHY_INTF_MII            0
  22#define PHY_INTF_RGMII          1
  23#define PHY_INTF_RMII           4
  24#define RMII_CLK_SRC_RXC        BIT(4)
  25#define RMII_CLK_SRC_INTERNAL   BIT(5)
  26
  27#define PERI_ETH_DLY    0x428
  28#define ETH_DLY_GTXC_INV        BIT(6)
  29#define ETH_DLY_GTXC_ENABLE     BIT(5)
  30#define ETH_DLY_GTXC_STAGES     GENMASK(4, 0)
  31#define ETH_DLY_TXC_INV         BIT(20)
  32#define ETH_DLY_TXC_ENABLE      BIT(19)
  33#define ETH_DLY_TXC_STAGES      GENMASK(18, 14)
  34#define ETH_DLY_RXC_INV         BIT(13)
  35#define ETH_DLY_RXC_ENABLE      BIT(12)
  36#define ETH_DLY_RXC_STAGES      GENMASK(11, 7)
  37
  38#define PERI_ETH_DLY_FINE       0x800
  39#define ETH_RMII_DLY_TX_INV     BIT(2)
  40#define ETH_FINE_DLY_GTXC       BIT(1)
  41#define ETH_FINE_DLY_RXC        BIT(0)
  42
  43struct mac_delay_struct {
  44        u32 tx_delay;
  45        u32 rx_delay;
  46        bool tx_inv;
  47        bool rx_inv;
  48};
  49
  50struct mediatek_dwmac_plat_data {
  51        const struct mediatek_dwmac_variant *variant;
  52        struct mac_delay_struct mac_delay;
  53        struct clk_bulk_data *clks;
  54        struct device_node *np;
  55        struct regmap *peri_regmap;
  56        struct device *dev;
  57        phy_interface_t phy_mode;
  58        int num_clks_to_config;
  59        bool rmii_clk_from_mac;
  60        bool rmii_rxc;
  61};
  62
  63struct mediatek_dwmac_variant {
  64        int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat);
  65        int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat);
  66
  67        /* clock ids to be requested */
  68        const char * const *clk_list;
  69        int num_clks;
  70
  71        u32 dma_bit_mask;
  72        u32 rx_delay_max;
  73        u32 tx_delay_max;
  74};
  75
  76/* list of clocks required for mac */
  77static const char * const mt2712_dwmac_clk_l[] = {
  78        "axi", "apb", "mac_main", "ptp_ref", "rmii_internal"
  79};
  80
  81static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat)
  82{
  83        int rmii_clk_from_mac = plat->rmii_clk_from_mac ? RMII_CLK_SRC_INTERNAL : 0;
  84        int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0;
  85        u32 intf_val = 0;
  86
  87        /* The clock labeled as "rmii_internal" in mt2712_dwmac_clk_l is needed
  88         * only in RMII(when MAC provides the reference clock), and useless for
  89         * RGMII/MII/RMII(when PHY provides the reference clock).
  90         * num_clks_to_config indicates the real number of clocks should be
  91         * configured, equals to (plat->variant->num_clks - 1) in default for all the case,
  92         * then +1 for rmii_clk_from_mac case.
  93         */
  94        plat->num_clks_to_config = plat->variant->num_clks - 1;
  95
  96        /* select phy interface in top control domain */
  97        switch (plat->phy_mode) {
  98        case PHY_INTERFACE_MODE_MII:
  99                intf_val |= PHY_INTF_MII;
 100                break;
 101        case PHY_INTERFACE_MODE_RMII:
 102                if (plat->rmii_clk_from_mac)
 103                        plat->num_clks_to_config++;
 104                intf_val |= (PHY_INTF_RMII | rmii_rxc | rmii_clk_from_mac);
 105                break;
 106        case PHY_INTERFACE_MODE_RGMII:
 107        case PHY_INTERFACE_MODE_RGMII_TXID:
 108        case PHY_INTERFACE_MODE_RGMII_RXID:
 109        case PHY_INTERFACE_MODE_RGMII_ID:
 110                intf_val |= PHY_INTF_RGMII;
 111                break;
 112        default:
 113                dev_err(plat->dev, "phy interface not supported\n");
 114                return -EINVAL;
 115        }
 116
 117        regmap_write(plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, intf_val);
 118
 119        return 0;
 120}
 121
 122static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
 123{
 124        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 125
 126        switch (plat->phy_mode) {
 127        case PHY_INTERFACE_MODE_MII:
 128        case PHY_INTERFACE_MODE_RMII:
 129                /* 550ps per stage for MII/RMII */
 130                mac_delay->tx_delay /= 550;
 131                mac_delay->rx_delay /= 550;
 132                break;
 133        case PHY_INTERFACE_MODE_RGMII:
 134        case PHY_INTERFACE_MODE_RGMII_TXID:
 135        case PHY_INTERFACE_MODE_RGMII_RXID:
 136        case PHY_INTERFACE_MODE_RGMII_ID:
 137                /* 170ps per stage for RGMII */
 138                mac_delay->tx_delay /= 170;
 139                mac_delay->rx_delay /= 170;
 140                break;
 141        default:
 142                dev_err(plat->dev, "phy interface not supported\n");
 143                break;
 144        }
 145}
 146
 147static void mt2712_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
 148{
 149        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 150
 151        switch (plat->phy_mode) {
 152        case PHY_INTERFACE_MODE_MII:
 153        case PHY_INTERFACE_MODE_RMII:
 154                /* 550ps per stage for MII/RMII */
 155                mac_delay->tx_delay *= 550;
 156                mac_delay->rx_delay *= 550;
 157                break;
 158        case PHY_INTERFACE_MODE_RGMII:
 159        case PHY_INTERFACE_MODE_RGMII_TXID:
 160        case PHY_INTERFACE_MODE_RGMII_RXID:
 161        case PHY_INTERFACE_MODE_RGMII_ID:
 162                /* 170ps per stage for RGMII */
 163                mac_delay->tx_delay *= 170;
 164                mac_delay->rx_delay *= 170;
 165                break;
 166        default:
 167                dev_err(plat->dev, "phy interface not supported\n");
 168                break;
 169        }
 170}
 171
 172static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
 173{
 174        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 175        u32 delay_val = 0, fine_val = 0;
 176
 177        mt2712_delay_ps2stage(plat);
 178
 179        switch (plat->phy_mode) {
 180        case PHY_INTERFACE_MODE_MII:
 181                delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->tx_delay);
 182                delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->tx_delay);
 183                delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->tx_inv);
 184
 185                delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 186                delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 187                delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 188                break;
 189        case PHY_INTERFACE_MODE_RMII:
 190                if (plat->rmii_clk_from_mac) {
 191                        /* case 1: mac provides the rmii reference clock,
 192                         * and the clock output to TXC pin.
 193                         * The egress timing can be adjusted by GTXC delay macro circuit.
 194                         * The ingress timing can be adjusted by TXC delay macro circuit.
 195                         */
 196                        delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
 197                        delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
 198                        delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);
 199
 200                        delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
 201                        delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
 202                        delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
 203                } else {
 204                        /* case 2: the rmii reference clock is from external phy,
 205                         * and the property "rmii_rxc" indicates which pin(TXC/RXC)
 206                         * the reference clk is connected to. The reference clock is a
 207                         * received signal, so rx_delay/rx_inv are used to indicate
 208                         * the reference clock timing adjustment
 209                         */
 210                        if (plat->rmii_rxc) {
 211                                /* the rmii reference clock from outside is connected
 212                                 * to RXC pin, the reference clock will be adjusted
 213                                 * by RXC delay macro circuit.
 214                                 */
 215                                delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 216                                delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 217                                delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 218                        } else {
 219                                /* the rmii reference clock from outside is connected
 220                                 * to TXC pin, the reference clock will be adjusted
 221                                 * by TXC delay macro circuit.
 222                                 */
 223                                delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
 224                                delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
 225                                delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);
 226                        }
 227                        /* tx_inv will inverse the tx clock inside mac relateive to
 228                         * reference clock from external phy,
 229                         * and this bit is located in the same register with fine-tune
 230                         */
 231                        if (mac_delay->tx_inv)
 232                                fine_val = ETH_RMII_DLY_TX_INV;
 233                }
 234                break;
 235        case PHY_INTERFACE_MODE_RGMII:
 236        case PHY_INTERFACE_MODE_RGMII_TXID:
 237        case PHY_INTERFACE_MODE_RGMII_RXID:
 238        case PHY_INTERFACE_MODE_RGMII_ID:
 239                fine_val = ETH_FINE_DLY_GTXC | ETH_FINE_DLY_RXC;
 240
 241                delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
 242                delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
 243                delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
 244
 245                delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 246                delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 247                delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 248                break;
 249        default:
 250                dev_err(plat->dev, "phy interface not supported\n");
 251                return -EINVAL;
 252        }
 253        regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val);
 254        regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val);
 255
 256        mt2712_delay_stage2ps(plat);
 257
 258        return 0;
 259}
 260
 261static const struct mediatek_dwmac_variant mt2712_gmac_variant = {
 262                .dwmac_set_phy_interface = mt2712_set_interface,
 263                .dwmac_set_delay = mt2712_set_delay,
 264                .clk_list = mt2712_dwmac_clk_l,
 265                .num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l),
 266                .dma_bit_mask = 33,
 267                .rx_delay_max = 17600,
 268                .tx_delay_max = 17600,
 269};
 270
 271static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat)
 272{
 273        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 274        u32 tx_delay_ps, rx_delay_ps;
 275        int err;
 276
 277        plat->peri_regmap = syscon_regmap_lookup_by_phandle(plat->np, "mediatek,pericfg");
 278        if (IS_ERR(plat->peri_regmap)) {
 279                dev_err(plat->dev, "Failed to get pericfg syscon\n");
 280                return PTR_ERR(plat->peri_regmap);
 281        }
 282
 283        err = of_get_phy_mode(plat->np, &plat->phy_mode);
 284        if (err) {
 285                dev_err(plat->dev, "not find phy-mode\n");
 286                return err;
 287        }
 288
 289        if (!of_property_read_u32(plat->np, "mediatek,tx-delay-ps", &tx_delay_ps)) {
 290                if (tx_delay_ps < plat->variant->tx_delay_max) {
 291                        mac_delay->tx_delay = tx_delay_ps;
 292                } else {
 293                        dev_err(plat->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
 294                        return -EINVAL;
 295                }
 296        }
 297
 298        if (!of_property_read_u32(plat->np, "mediatek,rx-delay-ps", &rx_delay_ps)) {
 299                if (rx_delay_ps < plat->variant->rx_delay_max) {
 300                        mac_delay->rx_delay = rx_delay_ps;
 301                } else {
 302                        dev_err(plat->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
 303                        return -EINVAL;
 304                }
 305        }
 306
 307        mac_delay->tx_inv = of_property_read_bool(plat->np, "mediatek,txc-inverse");
 308        mac_delay->rx_inv = of_property_read_bool(plat->np, "mediatek,rxc-inverse");
 309        plat->rmii_rxc = of_property_read_bool(plat->np, "mediatek,rmii-rxc");
 310        plat->rmii_clk_from_mac = of_property_read_bool(plat->np, "mediatek,rmii-clk-from-mac");
 311
 312        return 0;
 313}
 314
 315static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat)
 316{
 317        const struct mediatek_dwmac_variant *variant = plat->variant;
 318        int i, num = variant->num_clks;
 319
 320        plat->clks = devm_kcalloc(plat->dev, num, sizeof(*plat->clks), GFP_KERNEL);
 321        if (!plat->clks)
 322                return -ENOMEM;
 323
 324        for (i = 0; i < num; i++)
 325                plat->clks[i].id = variant->clk_list[i];
 326
 327        plat->num_clks_to_config = variant->num_clks;
 328
 329        return devm_clk_bulk_get(plat->dev, num, plat->clks);
 330}
 331
 332static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
 333{
 334        struct mediatek_dwmac_plat_data *plat = priv;
 335        const struct mediatek_dwmac_variant *variant = plat->variant;
 336        int ret;
 337
 338        ret = dma_set_mask_and_coherent(plat->dev, DMA_BIT_MASK(variant->dma_bit_mask));
 339        if (ret) {
 340                dev_err(plat->dev, "No suitable DMA available, err = %d\n", ret);
 341                return ret;
 342        }
 343
 344        ret = variant->dwmac_set_phy_interface(plat);
 345        if (ret) {
 346                dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret);
 347                return ret;
 348        }
 349
 350        ret = variant->dwmac_set_delay(plat);
 351        if (ret) {
 352                dev_err(plat->dev, "failed to set delay value, err = %d\n", ret);
 353                return ret;
 354        }
 355
 356        ret = clk_bulk_prepare_enable(plat->num_clks_to_config, plat->clks);
 357        if (ret) {
 358                dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
 359                return ret;
 360        }
 361
 362        pm_runtime_enable(&pdev->dev);
 363        pm_runtime_get_sync(&pdev->dev);
 364
 365        return 0;
 366}
 367
 368static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
 369{
 370        struct mediatek_dwmac_plat_data *plat = priv;
 371
 372        clk_bulk_disable_unprepare(plat->num_clks_to_config, plat->clks);
 373
 374        pm_runtime_put_sync(&pdev->dev);
 375        pm_runtime_disable(&pdev->dev);
 376}
 377
 378static int mediatek_dwmac_probe(struct platform_device *pdev)
 379{
 380        struct mediatek_dwmac_plat_data *priv_plat;
 381        struct plat_stmmacenet_data *plat_dat;
 382        struct stmmac_resources stmmac_res;
 383        int ret;
 384
 385        priv_plat = devm_kzalloc(&pdev->dev, sizeof(*priv_plat), GFP_KERNEL);
 386        if (!priv_plat)
 387                return -ENOMEM;
 388
 389        priv_plat->variant = of_device_get_match_data(&pdev->dev);
 390        if (!priv_plat->variant) {
 391                dev_err(&pdev->dev, "Missing dwmac-mediatek variant\n");
 392                return -EINVAL;
 393        }
 394
 395        priv_plat->dev = &pdev->dev;
 396        priv_plat->np = pdev->dev.of_node;
 397
 398        ret = mediatek_dwmac_config_dt(priv_plat);
 399        if (ret)
 400                return ret;
 401
 402        ret = mediatek_dwmac_clk_init(priv_plat);
 403        if (ret)
 404                return ret;
 405
 406        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
 407        if (ret)
 408                return ret;
 409
 410        plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
 411        if (IS_ERR(plat_dat))
 412                return PTR_ERR(plat_dat);
 413
 414        plat_dat->interface = priv_plat->phy_mode;
 415        plat_dat->has_gmac4 = 1;
 416        plat_dat->has_gmac = 0;
 417        plat_dat->pmt = 0;
 418        plat_dat->riwt_off = 1;
 419        plat_dat->maxmtu = ETH_DATA_LEN;
 420        plat_dat->bsp_priv = priv_plat;
 421        plat_dat->init = mediatek_dwmac_init;
 422        plat_dat->exit = mediatek_dwmac_exit;
 423        mediatek_dwmac_init(pdev, priv_plat);
 424
 425        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 426        if (ret) {
 427                stmmac_remove_config_dt(pdev, plat_dat);
 428                return ret;
 429        }
 430
 431        return 0;
 432}
 433
 434static const struct of_device_id mediatek_dwmac_match[] = {
 435        { .compatible = "mediatek,mt2712-gmac",
 436          .data = &mt2712_gmac_variant },
 437        { }
 438};
 439
 440MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
 441
 442static struct platform_driver mediatek_dwmac_driver = {
 443        .probe  = mediatek_dwmac_probe,
 444        .remove = stmmac_pltfr_remove,
 445        .driver = {
 446                .name           = "dwmac-mediatek",
 447                .pm             = &stmmac_pltfr_pm_ops,
 448                .of_match_table = mediatek_dwmac_match,
 449        },
 450};
 451module_platform_driver(mediatek_dwmac_driver);
 452
 453MODULE_AUTHOR("Biao Huang <biao.huang@mediatek.com>");
 454MODULE_DESCRIPTION("MediaTek DWMAC specific glue layer");
 455MODULE_LICENSE("GPL v2");
 456