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        int phy_mode;
  58        bool rmii_rxc;
  59};
  60
  61struct mediatek_dwmac_variant {
  62        int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat);
  63        int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat);
  64
  65        /* clock ids to be requested */
  66        const char * const *clk_list;
  67        int num_clks;
  68
  69        u32 dma_bit_mask;
  70        u32 rx_delay_max;
  71        u32 tx_delay_max;
  72};
  73
  74/* list of clocks required for mac */
  75static const char * const mt2712_dwmac_clk_l[] = {
  76        "axi", "apb", "mac_main", "ptp_ref"
  77};
  78
  79static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat)
  80{
  81        int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0;
  82        u32 intf_val = 0;
  83
  84        /* select phy interface in top control domain */
  85        switch (plat->phy_mode) {
  86        case PHY_INTERFACE_MODE_MII:
  87                intf_val |= PHY_INTF_MII;
  88                break;
  89        case PHY_INTERFACE_MODE_RMII:
  90                intf_val |= (PHY_INTF_RMII | rmii_rxc);
  91                break;
  92        case PHY_INTERFACE_MODE_RGMII:
  93        case PHY_INTERFACE_MODE_RGMII_TXID:
  94        case PHY_INTERFACE_MODE_RGMII_RXID:
  95        case PHY_INTERFACE_MODE_RGMII_ID:
  96                intf_val |= PHY_INTF_RGMII;
  97                break;
  98        default:
  99                dev_err(plat->dev, "phy interface not supported\n");
 100                return -EINVAL;
 101        }
 102
 103        regmap_write(plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, intf_val);
 104
 105        return 0;
 106}
 107
 108static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
 109{
 110        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 111
 112        switch (plat->phy_mode) {
 113        case PHY_INTERFACE_MODE_MII:
 114        case PHY_INTERFACE_MODE_RMII:
 115                /* 550ps per stage for MII/RMII */
 116                mac_delay->tx_delay /= 550;
 117                mac_delay->rx_delay /= 550;
 118                break;
 119        case PHY_INTERFACE_MODE_RGMII:
 120        case PHY_INTERFACE_MODE_RGMII_TXID:
 121        case PHY_INTERFACE_MODE_RGMII_RXID:
 122        case PHY_INTERFACE_MODE_RGMII_ID:
 123                /* 170ps per stage for RGMII */
 124                mac_delay->tx_delay /= 170;
 125                mac_delay->rx_delay /= 170;
 126                break;
 127        default:
 128                dev_err(plat->dev, "phy interface not supported\n");
 129                break;
 130        }
 131}
 132
 133static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
 134{
 135        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 136        u32 delay_val = 0, fine_val = 0;
 137
 138        mt2712_delay_ps2stage(plat);
 139
 140        switch (plat->phy_mode) {
 141        case PHY_INTERFACE_MODE_MII:
 142                delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->tx_delay);
 143                delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->tx_delay);
 144                delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->tx_inv);
 145
 146                delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 147                delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 148                delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 149                break;
 150        case PHY_INTERFACE_MODE_RMII:
 151                /* the rmii reference clock is from external phy,
 152                 * and the property "rmii_rxc" indicates which pin(TXC/RXC)
 153                 * the reference clk is connected to. The reference clock is a
 154                 * received signal, so rx_delay/rx_inv are used to indicate
 155                 * the reference clock timing adjustment
 156                 */
 157                if (plat->rmii_rxc) {
 158                        /* the rmii reference clock from outside is connected
 159                         * to RXC pin, the reference clock will be adjusted
 160                         * by RXC delay macro circuit.
 161                         */
 162                        delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 163                        delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 164                        delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 165                } else {
 166                        /* the rmii reference clock from outside is connected
 167                         * to TXC pin, the reference clock will be adjusted
 168                         * by TXC delay macro circuit.
 169                         */
 170                        delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
 171                        delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
 172                        delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);
 173                }
 174                /* tx_inv will inverse the tx clock inside mac relateive to
 175                 * reference clock from external phy,
 176                 * and this bit is located in the same register with fine-tune
 177                 */
 178                if (mac_delay->tx_inv)
 179                        fine_val = ETH_RMII_DLY_TX_INV;
 180                break;
 181        case PHY_INTERFACE_MODE_RGMII:
 182        case PHY_INTERFACE_MODE_RGMII_TXID:
 183        case PHY_INTERFACE_MODE_RGMII_RXID:
 184        case PHY_INTERFACE_MODE_RGMII_ID:
 185                fine_val = ETH_FINE_DLY_GTXC | ETH_FINE_DLY_RXC;
 186
 187                delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
 188                delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
 189                delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
 190
 191                delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
 192                delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
 193                delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
 194                break;
 195        default:
 196                dev_err(plat->dev, "phy interface not supported\n");
 197                return -EINVAL;
 198        }
 199        regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val);
 200        regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val);
 201
 202        return 0;
 203}
 204
 205static const struct mediatek_dwmac_variant mt2712_gmac_variant = {
 206                .dwmac_set_phy_interface = mt2712_set_interface,
 207                .dwmac_set_delay = mt2712_set_delay,
 208                .clk_list = mt2712_dwmac_clk_l,
 209                .num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l),
 210                .dma_bit_mask = 33,
 211                .rx_delay_max = 17600,
 212                .tx_delay_max = 17600,
 213};
 214
 215static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat)
 216{
 217        struct mac_delay_struct *mac_delay = &plat->mac_delay;
 218        u32 tx_delay_ps, rx_delay_ps;
 219
 220        plat->peri_regmap = syscon_regmap_lookup_by_phandle(plat->np, "mediatek,pericfg");
 221        if (IS_ERR(plat->peri_regmap)) {
 222                dev_err(plat->dev, "Failed to get pericfg syscon\n");
 223                return PTR_ERR(plat->peri_regmap);
 224        }
 225
 226        plat->phy_mode = of_get_phy_mode(plat->np);
 227        if (plat->phy_mode < 0) {
 228                dev_err(plat->dev, "not find phy-mode\n");
 229                return -EINVAL;
 230        }
 231
 232        if (!of_property_read_u32(plat->np, "mediatek,tx-delay-ps", &tx_delay_ps)) {
 233                if (tx_delay_ps < plat->variant->tx_delay_max) {
 234                        mac_delay->tx_delay = tx_delay_ps;
 235                } else {
 236                        dev_err(plat->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
 237                        return -EINVAL;
 238                }
 239        }
 240
 241        if (!of_property_read_u32(plat->np, "mediatek,rx-delay-ps", &rx_delay_ps)) {
 242                if (rx_delay_ps < plat->variant->rx_delay_max) {
 243                        mac_delay->rx_delay = rx_delay_ps;
 244                } else {
 245                        dev_err(plat->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
 246                        return -EINVAL;
 247                }
 248        }
 249
 250        mac_delay->tx_inv = of_property_read_bool(plat->np, "mediatek,txc-inverse");
 251        mac_delay->rx_inv = of_property_read_bool(plat->np, "mediatek,rxc-inverse");
 252        plat->rmii_rxc = of_property_read_bool(plat->np, "mediatek,rmii-rxc");
 253
 254        return 0;
 255}
 256
 257static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat)
 258{
 259        const struct mediatek_dwmac_variant *variant = plat->variant;
 260        int i, num = variant->num_clks;
 261
 262        plat->clks = devm_kcalloc(plat->dev, num, sizeof(*plat->clks), GFP_KERNEL);
 263        if (!plat->clks)
 264                return -ENOMEM;
 265
 266        for (i = 0; i < num; i++)
 267                plat->clks[i].id = variant->clk_list[i];
 268
 269        return devm_clk_bulk_get(plat->dev, num, plat->clks);
 270}
 271
 272static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
 273{
 274        struct mediatek_dwmac_plat_data *plat = priv;
 275        const struct mediatek_dwmac_variant *variant = plat->variant;
 276        int ret;
 277
 278        ret = dma_set_mask_and_coherent(plat->dev, DMA_BIT_MASK(variant->dma_bit_mask));
 279        if (ret) {
 280                dev_err(plat->dev, "No suitable DMA available, err = %d\n", ret);
 281                return ret;
 282        }
 283
 284        ret = variant->dwmac_set_phy_interface(plat);
 285        if (ret) {
 286                dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret);
 287                return ret;
 288        }
 289
 290        ret = variant->dwmac_set_delay(plat);
 291        if (ret) {
 292                dev_err(plat->dev, "failed to set delay value, err = %d\n", ret);
 293                return ret;
 294        }
 295
 296        ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks);
 297        if (ret) {
 298                dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
 299                return ret;
 300        }
 301
 302        pm_runtime_enable(&pdev->dev);
 303        pm_runtime_get_sync(&pdev->dev);
 304
 305        return 0;
 306}
 307
 308static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
 309{
 310        struct mediatek_dwmac_plat_data *plat = priv;
 311        const struct mediatek_dwmac_variant *variant = plat->variant;
 312
 313        clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
 314
 315        pm_runtime_put_sync(&pdev->dev);
 316        pm_runtime_disable(&pdev->dev);
 317}
 318
 319static int mediatek_dwmac_probe(struct platform_device *pdev)
 320{
 321        struct mediatek_dwmac_plat_data *priv_plat;
 322        struct plat_stmmacenet_data *plat_dat;
 323        struct stmmac_resources stmmac_res;
 324        int ret;
 325
 326        priv_plat = devm_kzalloc(&pdev->dev, sizeof(*priv_plat), GFP_KERNEL);
 327        if (!priv_plat)
 328                return -ENOMEM;
 329
 330        priv_plat->variant = of_device_get_match_data(&pdev->dev);
 331        if (!priv_plat->variant) {
 332                dev_err(&pdev->dev, "Missing dwmac-mediatek variant\n");
 333                return -EINVAL;
 334        }
 335
 336        priv_plat->dev = &pdev->dev;
 337        priv_plat->np = pdev->dev.of_node;
 338
 339        ret = mediatek_dwmac_config_dt(priv_plat);
 340        if (ret)
 341                return ret;
 342
 343        ret = mediatek_dwmac_clk_init(priv_plat);
 344        if (ret)
 345                return ret;
 346
 347        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
 348        if (ret)
 349                return ret;
 350
 351        plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
 352        if (IS_ERR(plat_dat))
 353                return PTR_ERR(plat_dat);
 354
 355        plat_dat->interface = priv_plat->phy_mode;
 356        plat_dat->has_gmac4 = 1;
 357        plat_dat->has_gmac = 0;
 358        plat_dat->pmt = 0;
 359        plat_dat->riwt_off = 1;
 360        plat_dat->maxmtu = ETH_DATA_LEN;
 361        plat_dat->bsp_priv = priv_plat;
 362        plat_dat->init = mediatek_dwmac_init;
 363        plat_dat->exit = mediatek_dwmac_exit;
 364        mediatek_dwmac_init(pdev, priv_plat);
 365
 366        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 367        if (ret) {
 368                stmmac_remove_config_dt(pdev, plat_dat);
 369                return ret;
 370        }
 371
 372        return 0;
 373}
 374
 375static const struct of_device_id mediatek_dwmac_match[] = {
 376        { .compatible = "mediatek,mt2712-gmac",
 377          .data = &mt2712_gmac_variant },
 378        { }
 379};
 380
 381MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
 382
 383static struct platform_driver mediatek_dwmac_driver = {
 384        .probe  = mediatek_dwmac_probe,
 385        .remove = stmmac_pltfr_remove,
 386        .driver = {
 387                .name           = "dwmac-mediatek",
 388                .pm             = &stmmac_pltfr_pm_ops,
 389                .of_match_table = mediatek_dwmac_match,
 390        },
 391};
 392module_platform_driver(mediatek_dwmac_driver);
 393
 394MODULE_AUTHOR("Biao Huang <biao.huang@mediatek.com>");
 395MODULE_DESCRIPTION("MediaTek DWMAC specific glue layer");
 396MODULE_LICENSE("GPL v2");
 397