root/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mt2712_set_interface
  2. mt2712_delay_ps2stage
  3. mt2712_set_delay
  4. mediatek_dwmac_config_dt
  5. mediatek_dwmac_clk_init
  6. mediatek_dwmac_init
  7. mediatek_dwmac_exit
  8. mediatek_dwmac_probe

   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 
  43 struct mac_delay_struct {
  44         u32 tx_delay;
  45         u32 rx_delay;
  46         bool tx_inv;
  47         bool rx_inv;
  48 };
  49 
  50 struct 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 
  61 struct 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 */
  75 static const char * const mt2712_dwmac_clk_l[] = {
  76         "axi", "apb", "mac_main", "ptp_ref"
  77 };
  78 
  79 static 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 
 108 static 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 
 133 static 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 
 205 static 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 
 215 static 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 
 257 static 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 
 272 static 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 
 308 static 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 
 319 static 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 
 375 static const struct of_device_id mediatek_dwmac_match[] = {
 376         { .compatible = "mediatek,mt2712-gmac",
 377           .data = &mt2712_gmac_variant },
 378         { }
 379 };
 380 
 381 MODULE_DEVICE_TABLE(of, mediatek_dwmac_match);
 382 
 383 static 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 };
 392 module_platform_driver(mediatek_dwmac_driver);
 393 
 394 MODULE_AUTHOR("Biao Huang <biao.huang@mediatek.com>");
 395 MODULE_DESCRIPTION("MediaTek DWMAC specific glue layer");
 396 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */