0001
0002
0003
0004
0005
0006
0007
0008
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
0024 #define OXNAS_DWMAC_CTRL_REGOFFSET 0x78
0025 #define OXNAS_DWMAC_DELAY_REGOFFSET 0x100
0026
0027
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
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
0075 value |= BIT(DWMAC_CKEN_GTX) |
0076
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
0094 value |= BIT(DWMAC_CKEN_GTX) |
0095
0096 BIT(DWMAC_SIMPLE_MUX) |
0097
0098 BIT(DWMAC_AUTO_TX_SOURCE) |
0099
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
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
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");