Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Adaptrum Anarion DWMAC glue layer
0004  *
0005  * Copyright (C) 2017, Adaptrum, Inc.
0006  * (Written by Alexandru Gagniuc <alex.g at adaptrum.com> for Adaptrum, Inc.)
0007  */
0008 
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/of_net.h>
0012 #include <linux/stmmac.h>
0013 
0014 #include "stmmac.h"
0015 #include "stmmac_platform.h"
0016 
0017 #define GMAC_RESET_CONTROL_REG      0
0018 #define GMAC_SW_CONFIG_REG      4
0019 #define  GMAC_CONFIG_INTF_SEL_MASK  (0x7 << 0)
0020 #define  GMAC_CONFIG_INTF_RGMII     (0x1 << 0)
0021 
0022 struct anarion_gmac {
0023     uintptr_t ctl_block;
0024     uint32_t phy_intf_sel;
0025 };
0026 
0027 static uint32_t gmac_read_reg(struct anarion_gmac *gmac, uint8_t reg)
0028 {
0029     return readl((void *)(gmac->ctl_block + reg));
0030 };
0031 
0032 static void gmac_write_reg(struct anarion_gmac *gmac, uint8_t reg, uint32_t val)
0033 {
0034     writel(val, (void *)(gmac->ctl_block + reg));
0035 }
0036 
0037 static int anarion_gmac_init(struct platform_device *pdev, void *priv)
0038 {
0039     uint32_t sw_config;
0040     struct anarion_gmac *gmac = priv;
0041 
0042     /* Reset logic, configure interface mode, then release reset. SIMPLE! */
0043     gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
0044 
0045     sw_config = gmac_read_reg(gmac, GMAC_SW_CONFIG_REG);
0046     sw_config &= ~GMAC_CONFIG_INTF_SEL_MASK;
0047     sw_config |= (gmac->phy_intf_sel & GMAC_CONFIG_INTF_SEL_MASK);
0048     gmac_write_reg(gmac, GMAC_SW_CONFIG_REG, sw_config);
0049 
0050     gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 0);
0051 
0052     return 0;
0053 }
0054 
0055 static void anarion_gmac_exit(struct platform_device *pdev, void *priv)
0056 {
0057     struct anarion_gmac *gmac = priv;
0058 
0059     gmac_write_reg(gmac, GMAC_RESET_CONTROL_REG, 1);
0060 }
0061 
0062 static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev)
0063 {
0064     struct anarion_gmac *gmac;
0065     phy_interface_t phy_mode;
0066     void __iomem *ctl_block;
0067     int err;
0068 
0069     ctl_block = devm_platform_ioremap_resource(pdev, 1);
0070     if (IS_ERR(ctl_block)) {
0071         dev_err(&pdev->dev, "Cannot get reset region (%ld)!\n",
0072             PTR_ERR(ctl_block));
0073         return ctl_block;
0074     }
0075 
0076     gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL);
0077     if (!gmac)
0078         return ERR_PTR(-ENOMEM);
0079 
0080     gmac->ctl_block = (uintptr_t)ctl_block;
0081 
0082     err = of_get_phy_mode(pdev->dev.of_node, &phy_mode);
0083     if (err)
0084         return ERR_PTR(err);
0085 
0086     switch (phy_mode) {
0087     case PHY_INTERFACE_MODE_RGMII:
0088         fallthrough;
0089     case PHY_INTERFACE_MODE_RGMII_ID:
0090     case PHY_INTERFACE_MODE_RGMII_RXID:
0091     case PHY_INTERFACE_MODE_RGMII_TXID:
0092         gmac->phy_intf_sel = GMAC_CONFIG_INTF_RGMII;
0093         break;
0094     default:
0095         dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n",
0096             phy_mode);
0097         return ERR_PTR(-ENOTSUPP);
0098     }
0099 
0100     return gmac;
0101 }
0102 
0103 static int anarion_dwmac_probe(struct platform_device *pdev)
0104 {
0105     int ret;
0106     struct anarion_gmac *gmac;
0107     struct plat_stmmacenet_data *plat_dat;
0108     struct stmmac_resources stmmac_res;
0109 
0110     ret = stmmac_get_platform_resources(pdev, &stmmac_res);
0111     if (ret)
0112         return ret;
0113 
0114     gmac = anarion_config_dt(pdev);
0115     if (IS_ERR(gmac))
0116         return PTR_ERR(gmac);
0117 
0118     plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
0119     if (IS_ERR(plat_dat))
0120         return PTR_ERR(plat_dat);
0121 
0122     plat_dat->init = anarion_gmac_init;
0123     plat_dat->exit = anarion_gmac_exit;
0124     anarion_gmac_init(pdev, gmac);
0125     plat_dat->bsp_priv = gmac;
0126 
0127     ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
0128     if (ret) {
0129         stmmac_remove_config_dt(pdev, plat_dat);
0130         return ret;
0131     }
0132 
0133     return 0;
0134 }
0135 
0136 static const struct of_device_id anarion_dwmac_match[] = {
0137     { .compatible = "adaptrum,anarion-gmac" },
0138     { }
0139 };
0140 MODULE_DEVICE_TABLE(of, anarion_dwmac_match);
0141 
0142 static struct platform_driver anarion_dwmac_driver = {
0143     .probe  = anarion_dwmac_probe,
0144     .remove = stmmac_pltfr_remove,
0145     .driver = {
0146         .name           = "anarion-dwmac",
0147         .pm     = &stmmac_pltfr_pm_ops,
0148         .of_match_table = anarion_dwmac_match,
0149     },
0150 };
0151 module_platform_driver(anarion_dwmac_driver);
0152 
0153 MODULE_DESCRIPTION("Adaptrum Anarion DWMAC specific glue layer");
0154 MODULE_AUTHOR("Alexandru Gagniuc <mr.nuke.me@gmail.com>");
0155 MODULE_LICENSE("GPL v2");