Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Oxford Semiconductor OXNAS DWMAC glue layer
0004  *
0005  * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
0006  * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
0007  * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
0008  * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
0009  */
0010 
0011 #include <linux/device.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/of_device.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018 #include <linux/mfd/syscon.h>
0019 #include <linux/stmmac.h>
0020 
0021 #include "stmmac_platform.h"
0022 
0023 /* System Control regmap offsets */
0024 #define OXNAS_DWMAC_CTRL_REGOFFSET  0x78
0025 #define OXNAS_DWMAC_DELAY_REGOFFSET 0x100
0026 
0027 /* Control Register */
0028 #define DWMAC_CKEN_RX_IN        14
0029 #define DWMAC_CKEN_RXN_OUT      13
0030 #define DWMAC_CKEN_RX_OUT       12
0031 #define DWMAC_CKEN_TX_IN        10
0032 #define DWMAC_CKEN_TXN_OUT      9
0033 #define DWMAC_CKEN_TX_OUT       8
0034 #define DWMAC_RX_SOURCE         7
0035 #define DWMAC_TX_SOURCE         6
0036 #define DWMAC_LOW_TX_SOURCE     4
0037 #define DWMAC_AUTO_TX_SOURCE    3
0038 #define DWMAC_RGMII             2
0039 #define DWMAC_SIMPLE_MUX        1
0040 #define DWMAC_CKEN_GTX          0
0041 
0042 /* Delay register */
0043 #define DWMAC_TX_VARDELAY_SHIFT     0
0044 #define DWMAC_TXN_VARDELAY_SHIFT    8
0045 #define DWMAC_RX_VARDELAY_SHIFT     16
0046 #define DWMAC_RXN_VARDELAY_SHIFT    24
0047 #define DWMAC_TX_VARDELAY(d)        ((d) << DWMAC_TX_VARDELAY_SHIFT)
0048 #define DWMAC_TXN_VARDELAY(d)       ((d) << DWMAC_TXN_VARDELAY_SHIFT)
0049 #define DWMAC_RX_VARDELAY(d)        ((d) << DWMAC_RX_VARDELAY_SHIFT)
0050 #define DWMAC_RXN_VARDELAY(d)       ((d) << DWMAC_RXN_VARDELAY_SHIFT)
0051 
0052 struct oxnas_dwmac;
0053 
0054 struct oxnas_dwmac_data {
0055     int (*setup)(struct oxnas_dwmac *dwmac);
0056 };
0057 
0058 struct oxnas_dwmac {
0059     struct device   *dev;
0060     struct clk  *clk;
0061     struct regmap   *regmap;
0062     const struct oxnas_dwmac_data   *data;
0063 };
0064 
0065 static int oxnas_dwmac_setup_ox810se(struct oxnas_dwmac *dwmac)
0066 {
0067     unsigned int value;
0068     int ret;
0069 
0070     ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
0071     if (ret < 0)
0072         return ret;
0073 
0074     /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
0075     value |= BIT(DWMAC_CKEN_GTX)        |
0076          /* Use simple mux for 25/125 Mhz clock switching */
0077          BIT(DWMAC_SIMPLE_MUX);
0078 
0079     regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
0080 
0081     return 0;
0082 }
0083 
0084 static int oxnas_dwmac_setup_ox820(struct oxnas_dwmac *dwmac)
0085 {
0086     unsigned int value;
0087     int ret;
0088 
0089     ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
0090     if (ret < 0)
0091         return ret;
0092 
0093     /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
0094     value |= BIT(DWMAC_CKEN_GTX)        |
0095          /* Use simple mux for 25/125 Mhz clock switching */
0096         BIT(DWMAC_SIMPLE_MUX)       |
0097         /* set auto switch tx clock source */
0098         BIT(DWMAC_AUTO_TX_SOURCE)   |
0099         /* enable tx & rx vardelay */
0100         BIT(DWMAC_CKEN_TX_OUT)      |
0101         BIT(DWMAC_CKEN_TXN_OUT) |
0102         BIT(DWMAC_CKEN_TX_IN)       |
0103         BIT(DWMAC_CKEN_RX_OUT)      |
0104         BIT(DWMAC_CKEN_RXN_OUT) |
0105         BIT(DWMAC_CKEN_RX_IN);
0106     regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
0107 
0108     /* set tx & rx vardelay */
0109     value = DWMAC_TX_VARDELAY(4)    |
0110         DWMAC_TXN_VARDELAY(2)   |
0111         DWMAC_RX_VARDELAY(10)   |
0112         DWMAC_RXN_VARDELAY(8);
0113     regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
0114 
0115     return 0;
0116 }
0117 
0118 static int oxnas_dwmac_init(struct platform_device *pdev, void *priv)
0119 {
0120     struct oxnas_dwmac *dwmac = priv;
0121     int ret;
0122 
0123     /* Reset HW here before changing the glue configuration */
0124     ret = device_reset(dwmac->dev);
0125     if (ret)
0126         return ret;
0127 
0128     ret = clk_prepare_enable(dwmac->clk);
0129     if (ret)
0130         return ret;
0131 
0132     ret = dwmac->data->setup(dwmac);
0133     if (ret)
0134         clk_disable_unprepare(dwmac->clk);
0135 
0136     return ret;
0137 }
0138 
0139 static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv)
0140 {
0141     struct oxnas_dwmac *dwmac = priv;
0142 
0143     clk_disable_unprepare(dwmac->clk);
0144 }
0145 
0146 static int oxnas_dwmac_probe(struct platform_device *pdev)
0147 {
0148     struct plat_stmmacenet_data *plat_dat;
0149     struct stmmac_resources stmmac_res;
0150     struct oxnas_dwmac *dwmac;
0151     int ret;
0152 
0153     ret = stmmac_get_platform_resources(pdev, &stmmac_res);
0154     if (ret)
0155         return ret;
0156 
0157     plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac);
0158     if (IS_ERR(plat_dat))
0159         return PTR_ERR(plat_dat);
0160 
0161     dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
0162     if (!dwmac) {
0163         ret = -ENOMEM;
0164         goto err_remove_config_dt;
0165     }
0166 
0167     dwmac->data = (const struct oxnas_dwmac_data *)of_device_get_match_data(&pdev->dev);
0168     if (!dwmac->data) {
0169         ret = -EINVAL;
0170         goto err_remove_config_dt;
0171     }
0172 
0173     dwmac->dev = &pdev->dev;
0174     plat_dat->bsp_priv = dwmac;
0175     plat_dat->init = oxnas_dwmac_init;
0176     plat_dat->exit = oxnas_dwmac_exit;
0177 
0178     dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
0179                             "oxsemi,sys-ctrl");
0180     if (IS_ERR(dwmac->regmap)) {
0181         dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
0182         ret = PTR_ERR(dwmac->regmap);
0183         goto err_remove_config_dt;
0184     }
0185 
0186     dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
0187     if (IS_ERR(dwmac->clk)) {
0188         ret = PTR_ERR(dwmac->clk);
0189         goto err_remove_config_dt;
0190     }
0191 
0192     ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv);
0193     if (ret)
0194         goto err_remove_config_dt;
0195 
0196     ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
0197     if (ret)
0198         goto err_dwmac_exit;
0199 
0200 
0201     return 0;
0202 
0203 err_dwmac_exit:
0204     oxnas_dwmac_exit(pdev, plat_dat->bsp_priv);
0205 err_remove_config_dt:
0206     stmmac_remove_config_dt(pdev, plat_dat);
0207 
0208     return ret;
0209 }
0210 
0211 static const struct oxnas_dwmac_data ox810se_dwmac_data = {
0212     .setup = oxnas_dwmac_setup_ox810se,
0213 };
0214 
0215 static const struct oxnas_dwmac_data ox820_dwmac_data = {
0216     .setup = oxnas_dwmac_setup_ox820,
0217 };
0218 
0219 static const struct of_device_id oxnas_dwmac_match[] = {
0220     {
0221         .compatible = "oxsemi,ox810se-dwmac",
0222         .data = &ox810se_dwmac_data,
0223     },
0224     {
0225         .compatible = "oxsemi,ox820-dwmac",
0226         .data = &ox820_dwmac_data,
0227     },
0228     { }
0229 };
0230 MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
0231 
0232 static struct platform_driver oxnas_dwmac_driver = {
0233     .probe  = oxnas_dwmac_probe,
0234     .remove = stmmac_pltfr_remove,
0235     .driver = {
0236         .name           = "oxnas-dwmac",
0237         .pm     = &stmmac_pltfr_pm_ops,
0238         .of_match_table = oxnas_dwmac_match,
0239     },
0240 };
0241 module_platform_driver(oxnas_dwmac_driver);
0242 
0243 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0244 MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer");
0245 MODULE_LICENSE("GPL v2");