linux/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * dwmac-ingenic.c - Ingenic SoCs DWMAC specific glue layer
   4 *
   5 * Copyright (c) 2021 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
   6 */
   7
   8#include <linux/bitfield.h>
   9#include <linux/clk.h>
  10#include <linux/kernel.h>
  11#include <linux/mfd/syscon.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_device.h>
  15#include <linux/of_net.h>
  16#include <linux/phy.h>
  17#include <linux/platform_device.h>
  18#include <linux/regmap.h>
  19#include <linux/slab.h>
  20#include <linux/stmmac.h>
  21
  22#include "stmmac_platform.h"
  23
  24#define MACPHYC_TXCLK_SEL_MASK          GENMASK(31, 31)
  25#define MACPHYC_TXCLK_SEL_OUTPUT        0x1
  26#define MACPHYC_TXCLK_SEL_INPUT         0x0
  27#define MACPHYC_MODE_SEL_MASK           GENMASK(31, 31)
  28#define MACPHYC_MODE_SEL_RMII           0x0
  29#define MACPHYC_TX_SEL_MASK                     GENMASK(19, 19)
  30#define MACPHYC_TX_SEL_ORIGIN           0x0
  31#define MACPHYC_TX_SEL_DELAY            0x1
  32#define MACPHYC_TX_DELAY_MASK           GENMASK(18, 12)
  33#define MACPHYC_RX_SEL_MASK                     GENMASK(11, 11)
  34#define MACPHYC_RX_SEL_ORIGIN           0x0
  35#define MACPHYC_RX_SEL_DELAY            0x1
  36#define MACPHYC_RX_DELAY_MASK           GENMASK(10, 4)
  37#define MACPHYC_SOFT_RST_MASK           GENMASK(3, 3)
  38#define MACPHYC_PHY_INFT_MASK           GENMASK(2, 0)
  39#define MACPHYC_PHY_INFT_RMII           0x4
  40#define MACPHYC_PHY_INFT_RGMII          0x1
  41#define MACPHYC_PHY_INFT_GMII           0x0
  42#define MACPHYC_PHY_INFT_MII            0x0
  43
  44#define MACPHYC_TX_DELAY_PS_MAX         2496
  45#define MACPHYC_TX_DELAY_PS_MIN         20
  46
  47#define MACPHYC_RX_DELAY_PS_MAX         2496
  48#define MACPHYC_RX_DELAY_PS_MIN         20
  49
  50enum ingenic_mac_version {
  51        ID_JZ4775,
  52        ID_X1000,
  53        ID_X1600,
  54        ID_X1830,
  55        ID_X2000,
  56};
  57
  58struct ingenic_mac {
  59        const struct ingenic_soc_info *soc_info;
  60        struct device *dev;
  61        struct regmap *regmap;
  62
  63        int rx_delay;
  64        int tx_delay;
  65};
  66
  67struct ingenic_soc_info {
  68        enum ingenic_mac_version version;
  69        u32 mask;
  70
  71        int (*set_mode)(struct plat_stmmacenet_data *plat_dat);
  72};
  73
  74static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat)
  75{
  76        struct ingenic_mac *mac = plat_dat->bsp_priv;
  77        int ret;
  78
  79        if (mac->soc_info->set_mode) {
  80                ret = mac->soc_info->set_mode(plat_dat);
  81                if (ret)
  82                        return ret;
  83        }
  84
  85        return 0;
  86}
  87
  88static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
  89{
  90        struct ingenic_mac *mac = plat_dat->bsp_priv;
  91        unsigned int val;
  92
  93        switch (plat_dat->interface) {
  94        case PHY_INTERFACE_MODE_MII:
  95                val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
  96                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII);
  97                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n");
  98                break;
  99
 100        case PHY_INTERFACE_MODE_GMII:
 101                val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
 102                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII);
 103                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n");
 104                break;
 105
 106        case PHY_INTERFACE_MODE_RMII:
 107                val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
 108                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
 109                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
 110                break;
 111
 112        case PHY_INTERFACE_MODE_RGMII:
 113        case PHY_INTERFACE_MODE_RGMII_ID:
 114        case PHY_INTERFACE_MODE_RGMII_TXID:
 115        case PHY_INTERFACE_MODE_RGMII_RXID:
 116                val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) |
 117                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
 118                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
 119                break;
 120
 121        default:
 122                dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
 123                return -EINVAL;
 124        }
 125
 126        /* Update MAC PHY control register */
 127        return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
 128}
 129
 130static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
 131{
 132        struct ingenic_mac *mac = plat_dat->bsp_priv;
 133
 134        switch (plat_dat->interface) {
 135        case PHY_INTERFACE_MODE_RMII:
 136                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
 137                break;
 138
 139        default:
 140                dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
 141                return -EINVAL;
 142        }
 143
 144        /* Update MAC PHY control register */
 145        return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0);
 146}
 147
 148static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
 149{
 150        struct ingenic_mac *mac = plat_dat->bsp_priv;
 151        unsigned int val;
 152
 153        switch (plat_dat->interface) {
 154        case PHY_INTERFACE_MODE_RMII:
 155                val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
 156                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
 157                break;
 158
 159        default:
 160                dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
 161                return -EINVAL;
 162        }
 163
 164        /* Update MAC PHY control register */
 165        return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
 166}
 167
 168static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
 169{
 170        struct ingenic_mac *mac = plat_dat->bsp_priv;
 171        unsigned int val;
 172
 173        switch (plat_dat->interface) {
 174        case PHY_INTERFACE_MODE_RMII:
 175                val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) |
 176                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
 177                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
 178                break;
 179
 180        default:
 181                dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
 182                return -EINVAL;
 183        }
 184
 185        /* Update MAC PHY control register */
 186        return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
 187}
 188
 189static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat)
 190{
 191        struct ingenic_mac *mac = plat_dat->bsp_priv;
 192        unsigned int val;
 193
 194        switch (plat_dat->interface) {
 195        case PHY_INTERFACE_MODE_RMII:
 196                val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) |
 197                          FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) |
 198                          FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII);
 199                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n");
 200                break;
 201
 202        case PHY_INTERFACE_MODE_RGMII:
 203        case PHY_INTERFACE_MODE_RGMII_ID:
 204        case PHY_INTERFACE_MODE_RGMII_TXID:
 205        case PHY_INTERFACE_MODE_RGMII_RXID:
 206                val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII);
 207
 208                if (mac->tx_delay == 0)
 209                        val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN);
 210                else
 211                        val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) |
 212                                   FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1);
 213
 214                if (mac->rx_delay == 0)
 215                        val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN);
 216                else
 217                        val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) |
 218                                   FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1);
 219
 220                dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n");
 221                break;
 222
 223        default:
 224                dev_err(mac->dev, "Unsupported interface %d", plat_dat->interface);
 225                return -EINVAL;
 226        }
 227
 228        /* Update MAC PHY control register */
 229        return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val);
 230}
 231
 232static int ingenic_mac_probe(struct platform_device *pdev)
 233{
 234        struct plat_stmmacenet_data *plat_dat;
 235        struct stmmac_resources stmmac_res;
 236        struct ingenic_mac *mac;
 237        const struct ingenic_soc_info *data;
 238        u32 tx_delay_ps, rx_delay_ps;
 239        int ret;
 240
 241        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
 242        if (ret)
 243                return ret;
 244
 245        plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
 246        if (IS_ERR(plat_dat))
 247                return PTR_ERR(plat_dat);
 248
 249        mac = devm_kzalloc(&pdev->dev, sizeof(*mac), GFP_KERNEL);
 250        if (!mac) {
 251                ret = -ENOMEM;
 252                goto err_remove_config_dt;
 253        }
 254
 255        data = of_device_get_match_data(&pdev->dev);
 256        if (!data) {
 257                dev_err(&pdev->dev, "No of match data provided\n");
 258                ret = -EINVAL;
 259                goto err_remove_config_dt;
 260        }
 261
 262        /* Get MAC PHY control register */
 263        mac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "mode-reg");
 264        if (IS_ERR(mac->regmap)) {
 265                dev_err(&pdev->dev, "%s: Failed to get syscon regmap\n", __func__);
 266                ret = PTR_ERR(mac->regmap);
 267                goto err_remove_config_dt;
 268        }
 269
 270        if (!of_property_read_u32(pdev->dev.of_node, "tx-clk-delay-ps", &tx_delay_ps)) {
 271                if (tx_delay_ps >= MACPHYC_TX_DELAY_PS_MIN &&
 272                        tx_delay_ps <= MACPHYC_TX_DELAY_PS_MAX) {
 273                        mac->tx_delay = tx_delay_ps * 1000;
 274                } else {
 275                        dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
 276                        return -EINVAL;
 277                }
 278        }
 279
 280        if (!of_property_read_u32(pdev->dev.of_node, "rx-clk-delay-ps", &rx_delay_ps)) {
 281                if (rx_delay_ps >= MACPHYC_RX_DELAY_PS_MIN &&
 282                        rx_delay_ps <= MACPHYC_RX_DELAY_PS_MAX) {
 283                        mac->rx_delay = rx_delay_ps * 1000;
 284                } else {
 285                        dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
 286                        return -EINVAL;
 287                }
 288        }
 289
 290        mac->soc_info = data;
 291        mac->dev = &pdev->dev;
 292
 293        plat_dat->bsp_priv = mac;
 294
 295        ret = ingenic_mac_init(plat_dat);
 296        if (ret)
 297                goto err_remove_config_dt;
 298
 299        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
 300        if (ret)
 301                goto err_remove_config_dt;
 302
 303        return 0;
 304
 305err_remove_config_dt:
 306        stmmac_remove_config_dt(pdev, plat_dat);
 307
 308        return ret;
 309}
 310
 311#ifdef CONFIG_PM_SLEEP
 312static int ingenic_mac_suspend(struct device *dev)
 313{
 314        int ret;
 315
 316        ret = stmmac_suspend(dev);
 317
 318        return ret;
 319}
 320
 321static int ingenic_mac_resume(struct device *dev)
 322{
 323        struct net_device *ndev = dev_get_drvdata(dev);
 324        struct stmmac_priv *priv = netdev_priv(ndev);
 325        int ret;
 326
 327        ret = ingenic_mac_init(priv->plat);
 328        if (ret)
 329                return ret;
 330
 331        ret = stmmac_resume(dev);
 332
 333        return ret;
 334}
 335#endif /* CONFIG_PM_SLEEP */
 336
 337static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume);
 338
 339static struct ingenic_soc_info jz4775_soc_info = {
 340        .version = ID_JZ4775,
 341        .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
 342
 343        .set_mode = jz4775_mac_set_mode,
 344};
 345
 346static struct ingenic_soc_info x1000_soc_info = {
 347        .version = ID_X1000,
 348        .mask = MACPHYC_SOFT_RST_MASK,
 349
 350        .set_mode = x1000_mac_set_mode,
 351};
 352
 353static struct ingenic_soc_info x1600_soc_info = {
 354        .version = ID_X1600,
 355        .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
 356
 357        .set_mode = x1600_mac_set_mode,
 358};
 359
 360static struct ingenic_soc_info x1830_soc_info = {
 361        .version = ID_X1830,
 362        .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
 363
 364        .set_mode = x1830_mac_set_mode,
 365};
 366
 367static struct ingenic_soc_info x2000_soc_info = {
 368        .version = ID_X2000,
 369        .mask = MACPHYC_TX_SEL_MASK | MACPHYC_TX_DELAY_MASK | MACPHYC_RX_SEL_MASK |
 370                        MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK,
 371
 372        .set_mode = x2000_mac_set_mode,
 373};
 374
 375static const struct of_device_id ingenic_mac_of_matches[] = {
 376        { .compatible = "ingenic,jz4775-mac", .data = &jz4775_soc_info },
 377        { .compatible = "ingenic,x1000-mac", .data = &x1000_soc_info },
 378        { .compatible = "ingenic,x1600-mac", .data = &x1600_soc_info },
 379        { .compatible = "ingenic,x1830-mac", .data = &x1830_soc_info },
 380        { .compatible = "ingenic,x2000-mac", .data = &x2000_soc_info },
 381        { }
 382};
 383MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches);
 384
 385static struct platform_driver ingenic_mac_driver = {
 386        .probe          = ingenic_mac_probe,
 387        .remove         = stmmac_pltfr_remove,
 388        .driver         = {
 389                .name   = "ingenic-mac",
 390                .pm             = pm_ptr(&ingenic_mac_pm_ops),
 391                .of_match_table = ingenic_mac_of_matches,
 392        },
 393};
 394module_platform_driver(ingenic_mac_driver);
 395
 396MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
 397MODULE_DESCRIPTION("Ingenic SoCs DWMAC specific glue layer");
 398MODULE_LICENSE("GPL v2");
 399