110145f7cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22d1611afSAlexandru Gagniuc /*
32d1611afSAlexandru Gagniuc * Adaptrum Anarion DWMAC glue layer
42d1611afSAlexandru Gagniuc *
52d1611afSAlexandru Gagniuc * Copyright (C) 2017, Adaptrum, Inc.
62d1611afSAlexandru Gagniuc * (Written by Alexandru Gagniuc <alex.g at adaptrum.com> for Adaptrum, Inc.)
72d1611afSAlexandru Gagniuc */
82d1611afSAlexandru Gagniuc
92d1611afSAlexandru Gagniuc #include <linux/io.h>
102d1611afSAlexandru Gagniuc #include <linux/of.h>
112d1611afSAlexandru Gagniuc #include <linux/of_net.h>
122d1611afSAlexandru Gagniuc #include <linux/stmmac.h>
132d1611afSAlexandru Gagniuc
142d1611afSAlexandru Gagniuc #include "stmmac.h"
152d1611afSAlexandru Gagniuc #include "stmmac_platform.h"
162d1611afSAlexandru Gagniuc
172d1611afSAlexandru Gagniuc #define GMAC_RESET_CONTROL_REG 0
182d1611afSAlexandru Gagniuc #define GMAC_SW_CONFIG_REG 4
192d1611afSAlexandru Gagniuc #define GMAC_CONFIG_INTF_SEL_MASK (0x7 << 0)
202d1611afSAlexandru Gagniuc #define GMAC_CONFIG_INTF_RGMII (0x1 << 0)
212d1611afSAlexandru Gagniuc
222d1611afSAlexandru Gagniuc struct anarion_gmac {
239f12541dSSimon Horman void __iomem *ctl_block;
242d1611afSAlexandru Gagniuc uint32_t phy_intf_sel;
252d1611afSAlexandru Gagniuc };
262d1611afSAlexandru Gagniuc
gmac_read_reg(struct anarion_gmac * gmac,uint8_t reg)272d1611afSAlexandru Gagniuc static uint32_t gmac_read_reg(struct anarion_gmac *gmac, uint8_t reg)
282d1611afSAlexandru Gagniuc {
299f12541dSSimon Horman return readl(gmac->ctl_block + reg);
302d1611afSAlexandru Gagniuc };
312d1611afSAlexandru Gagniuc
gmac_write_reg(struct anarion_gmac * gmac,uint8_t reg,uint32_t val)322d1611afSAlexandru Gagniuc static void gmac_write_reg(struct anarion_gmac *gmac, uint8_t reg, uint32_t val)
332d1611afSAlexandru Gagniuc {
349f12541dSSimon Horman writel(val, gmac->ctl_block + reg);
352d1611afSAlexandru Gagniuc }
362d1611afSAlexandru Gagniuc
anarion_gmac_init(struct platform_device * pdev,void * priv)372d1611afSAlexandru Gagniuc static int anarion_gmac_init(struct platform_device *pdev, void *priv)
382d1611afSAlexandru Gagniuc {
392d1611afSAlexandru Gagniuc uint32_t sw_config;
402d1611afSAlexandru Gagniuc struct anarion_gmac *gmac = priv;
412d1611afSAlexandru Gagniuc
422d1611afSAlexandru Gagniuc /* Reset logic, configure interface mode, then release reset. SIMPLE! */
432d1611afSAlexandru Gagniuc gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
442d1611afSAlexandru Gagniuc
452d1611afSAlexandru Gagniuc sw_config = gmac_read_reg(gmac, GMAC_SW_CONFIG_REG);
462d1611afSAlexandru Gagniuc sw_config &= ~GMAC_CONFIG_INTF_SEL_MASK;
472d1611afSAlexandru Gagniuc sw_config |= (gmac->phy_intf_sel & GMAC_CONFIG_INTF_SEL_MASK);
482d1611afSAlexandru Gagniuc gmac_write_reg(gmac, GMAC_SW_CONFIG_REG, sw_config);
492d1611afSAlexandru Gagniuc
502d1611afSAlexandru Gagniuc gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 0);
512d1611afSAlexandru Gagniuc
522d1611afSAlexandru Gagniuc return 0;
532d1611afSAlexandru Gagniuc }
542d1611afSAlexandru Gagniuc
anarion_gmac_exit(struct platform_device * pdev,void * priv)552d1611afSAlexandru Gagniuc static void anarion_gmac_exit(struct platform_device *pdev, void *priv)
562d1611afSAlexandru Gagniuc {
572d1611afSAlexandru Gagniuc struct anarion_gmac *gmac = priv;
582d1611afSAlexandru Gagniuc
592d1611afSAlexandru Gagniuc gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
602d1611afSAlexandru Gagniuc }
612d1611afSAlexandru Gagniuc
anarion_config_dt(struct platform_device * pdev)622d1611afSAlexandru Gagniuc static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev)
632d1611afSAlexandru Gagniuc {
642d1611afSAlexandru Gagniuc struct anarion_gmac *gmac;
650c65b2b9SAndrew Lunn phy_interface_t phy_mode;
660c65b2b9SAndrew Lunn void __iomem *ctl_block;
670c65b2b9SAndrew Lunn int err;
682d1611afSAlexandru Gagniuc
69ad124aa3SYueHaibing ctl_block = devm_platform_ioremap_resource(pdev, 1);
702d1611afSAlexandru Gagniuc if (IS_ERR(ctl_block)) {
71*51fe084bSSimon Horman err = PTR_ERR(ctl_block);
72*51fe084bSSimon Horman dev_err(&pdev->dev, "Cannot get reset region (%d)!\n", err);
73*51fe084bSSimon Horman return ERR_PTR(err);
742d1611afSAlexandru Gagniuc }
752d1611afSAlexandru Gagniuc
762d1611afSAlexandru Gagniuc gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL);
772d1611afSAlexandru Gagniuc if (!gmac)
782d1611afSAlexandru Gagniuc return ERR_PTR(-ENOMEM);
792d1611afSAlexandru Gagniuc
809f12541dSSimon Horman gmac->ctl_block = ctl_block;
812d1611afSAlexandru Gagniuc
820c65b2b9SAndrew Lunn err = of_get_phy_mode(pdev->dev.of_node, &phy_mode);
830c65b2b9SAndrew Lunn if (err)
840c65b2b9SAndrew Lunn return ERR_PTR(err);
850c65b2b9SAndrew Lunn
862d1611afSAlexandru Gagniuc switch (phy_mode) {
87df561f66SGustavo A. R. Silva case PHY_INTERFACE_MODE_RGMII:
88df561f66SGustavo A. R. Silva fallthrough;
89df561f66SGustavo A. R. Silva case PHY_INTERFACE_MODE_RGMII_ID:
90df561f66SGustavo A. R. Silva case PHY_INTERFACE_MODE_RGMII_RXID:
912d1611afSAlexandru Gagniuc case PHY_INTERFACE_MODE_RGMII_TXID:
922d1611afSAlexandru Gagniuc gmac->phy_intf_sel = GMAC_CONFIG_INTF_RGMII;
932d1611afSAlexandru Gagniuc break;
942d1611afSAlexandru Gagniuc default:
952d1611afSAlexandru Gagniuc dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n",
962d1611afSAlexandru Gagniuc phy_mode);
972d1611afSAlexandru Gagniuc return ERR_PTR(-ENOTSUPP);
982d1611afSAlexandru Gagniuc }
992d1611afSAlexandru Gagniuc
1002d1611afSAlexandru Gagniuc return gmac;
1012d1611afSAlexandru Gagniuc }
1022d1611afSAlexandru Gagniuc
anarion_dwmac_probe(struct platform_device * pdev)1032d1611afSAlexandru Gagniuc static int anarion_dwmac_probe(struct platform_device *pdev)
1042d1611afSAlexandru Gagniuc {
1052d1611afSAlexandru Gagniuc int ret;
1062d1611afSAlexandru Gagniuc struct anarion_gmac *gmac;
1072d1611afSAlexandru Gagniuc struct plat_stmmacenet_data *plat_dat;
1082d1611afSAlexandru Gagniuc struct stmmac_resources stmmac_res;
1092d1611afSAlexandru Gagniuc
1102d1611afSAlexandru Gagniuc ret = stmmac_get_platform_resources(pdev, &stmmac_res);
1112d1611afSAlexandru Gagniuc if (ret)
1122d1611afSAlexandru Gagniuc return ret;
1132d1611afSAlexandru Gagniuc
1142d1611afSAlexandru Gagniuc gmac = anarion_config_dt(pdev);
1152d1611afSAlexandru Gagniuc if (IS_ERR(gmac))
1162d1611afSAlexandru Gagniuc return PTR_ERR(gmac);
1172d1611afSAlexandru Gagniuc
11883216e39SMichael Walle plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
1192d1611afSAlexandru Gagniuc if (IS_ERR(plat_dat))
1202d1611afSAlexandru Gagniuc return PTR_ERR(plat_dat);
1212d1611afSAlexandru Gagniuc
1222d1611afSAlexandru Gagniuc plat_dat->init = anarion_gmac_init;
1232d1611afSAlexandru Gagniuc plat_dat->exit = anarion_gmac_exit;
1242d1611afSAlexandru Gagniuc anarion_gmac_init(pdev, gmac);
1252d1611afSAlexandru Gagniuc plat_dat->bsp_priv = gmac;
1262d1611afSAlexandru Gagniuc
1272d1611afSAlexandru Gagniuc ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
1282d1611afSAlexandru Gagniuc if (ret) {
1292d1611afSAlexandru Gagniuc stmmac_remove_config_dt(pdev, plat_dat);
1302d1611afSAlexandru Gagniuc return ret;
1312d1611afSAlexandru Gagniuc }
1322d1611afSAlexandru Gagniuc
1332d1611afSAlexandru Gagniuc return 0;
1342d1611afSAlexandru Gagniuc }
1352d1611afSAlexandru Gagniuc
1362d1611afSAlexandru Gagniuc static const struct of_device_id anarion_dwmac_match[] = {
1372d1611afSAlexandru Gagniuc { .compatible = "adaptrum,anarion-gmac" },
1382d1611afSAlexandru Gagniuc { }
1392d1611afSAlexandru Gagniuc };
1402d1611afSAlexandru Gagniuc MODULE_DEVICE_TABLE(of, anarion_dwmac_match);
1412d1611afSAlexandru Gagniuc
1422d1611afSAlexandru Gagniuc static struct platform_driver anarion_dwmac_driver = {
1432d1611afSAlexandru Gagniuc .probe = anarion_dwmac_probe,
1442d1611afSAlexandru Gagniuc .remove_new = stmmac_pltfr_remove,
1452d1611afSAlexandru Gagniuc .driver = {
1462d1611afSAlexandru Gagniuc .name = "anarion-dwmac",
1472d1611afSAlexandru Gagniuc .pm = &stmmac_pltfr_pm_ops,
1482d1611afSAlexandru Gagniuc .of_match_table = anarion_dwmac_match,
1492d1611afSAlexandru Gagniuc },
1502d1611afSAlexandru Gagniuc };
1512d1611afSAlexandru Gagniuc module_platform_driver(anarion_dwmac_driver);
1522d1611afSAlexandru Gagniuc
1532d1611afSAlexandru Gagniuc MODULE_DESCRIPTION("Adaptrum Anarion DWMAC specific glue layer");
1542d1611afSAlexandru Gagniuc MODULE_AUTHOR("Alexandru Gagniuc <mr.nuke.me@gmail.com>");
1552d1611afSAlexandru Gagniuc MODULE_LICENSE("GPL v2");
156